Компонент не обновляется, даже если значение useState изменилось

#reactjs #react-hooks

Вопрос:

Я пытаюсь создать динамический раскрывающийся список с помощью начальной загрузки. Элементы в этом раскрывающемся списке будут меняться в зависимости от значения, выбранного в предыдущем раскрывающемся списке. Значение в предыдущем раскрывающемся списке успешно изменяется, и состояние также изменяется, но {Имя пользователя} не отображается повторно после каждого выбора.

 const users = ... // API call from server 

const [userName, setUserName] = useState([]);

useEffect(() => {
   console.log(userName) // userName successfully changes at each select
}, [userName]);

function handleSelect(event) {
   setUserName(event.target.value)
}

return (
   ...
   <Form.Group> 
      <Form.Label>
         Select User
      </Form.Label>

      // This part works fine 
      <Form.Control 
          as="select" 
          onChange={handleSelect} 
          className="form-select"
      > 
           {users.map(names => {
               <option key={names.value} > {names.name} </option>
           }
     </Form.Control> 

    <Dropdown> 
       // userName doesnt change 
       <Dropdown.Item> {userName} </Dropdown.Item> 
    <Dropdown>
   ...
 )
 

Комментарии:

1. Я не понимаю, если userName useEffect он обновился при входе в систему, это то же значение, которое использовалось при возврате рендеринга. Другими словами, это значение состояния для этого цикла визуализации. Можете ли вы создать работающий код и поле, воспроизводящее эту проблему, в котором мы можем проверять и отлаживать в режиме реального времени?

2. можете ли вы предоставить codesandbox для этого ?

3. Почему вы устанавливаете свое начальное состояние в виде массива? если это только одно имя пользователя

Ответ №1:

Примечание https://reactjs.org/docs/hooks-reference.html#usestate

В отличие от метода setState, найденного в компонентах класса, useState не объединяет объекты обновления автоматически. Вы можете повторить это поведение, объединив форму средства обновления функций с синтаксисом распространения объектов:

         function handleSelect(event) {
           setUserName((prevValues) => return [...prevValues, event.target.value])
        }
 

Комментарии:

1. Я думаю, что массив в качестве начального состояния является ошибкой, поскольку пользовательский интерфейс отображает select ввод, а обработчик изменений обрабатывает только одно значение. И тот факт, что правильное значение зарегистрировано в useEffect крючке, является подсказкой о том, что состояние обновляется правильно, как и ожидалось.

Ответ №2:

Я использовал тот же код, который вы предоставили, и он работает для меня.

Может быть, этот фрагмент поможет вам.

 // Get a hook function

const { useState, useEffect, Fragment } = React;
const { Form, Dropdown, Row, Col, Container } = ReactBootstrap;

const Example = ({}) => {
    const [userName, setUserName] = useState([]);
    const users = [
        { name: "abc", value: "abc" },
        { name: "xyz", value: "xyz" }
    ];

    function handleSelect(event) {
        setUserName(event.target.value);
    }

    return (
        <Container>
            <Row>
                <Col sm={6}>
                    <Form.Label>Select User</Form.Label>
                    <Form.Control as="select" onChange={handleSelect} className="form-select">
                        {users.map((val) => {
                            return <option key={val.value}> {val.name} </option>;
                        })}
                    </Form.Control>
                </Col>
            </Row>
            <Row>
             <Form.Label>Selected Value:</Form.Label>
                <Dropdown>
                    <Dropdown.Item>{userName}</Dropdown.Item>
                </Dropdown>
            </Row>
        </Container>
    );
};

// Render it
ReactDOM.render(<Example title="Example using Hooks:" />, document.getElementById("react")); 
 <link
  rel="stylesheet"  href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
  integrity="sha384-B0vP5xmATw1 K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2 l"
  crossorigin="anonymous"
/>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

<script
  src="https://unpkg.com/react-bootstrap@next/dist/react-bootstrap.min.js"
  crossorigin></script>
<div id="react"></div>