Функциональный компонент Ract не обновляется после изменения состояния

#reactjs #react-hooks #use-state #use-context

#reactjs #реагирующие хуки #use-state #использование-context

Вопрос:

Я пытался обновить состояние после того, как пользователь выберет выпадающий список, однако выбранный параметр никогда не изменяется. Смотрите gif — https://recordit.co/KH2Pqn34bp .

Я смущен тем, что в идеале после использования setFilterOptions для обновления состояния предполагается повторно отобразить этот компонент с новым значением, но этого не происходит. Кто-нибудь может помочь взглянуть? Чего мне здесь не хватает? Большое спасибо!

Пример кода в изолированной среде — https://codesandbox.io/s/react-select-default-value-forked-1ybdk?file=/index.js

 const SearchFilter = () => {
    const [filterOptions, setFilterOptions] = useContext(SearchFilterContext);  
    let curSort = filterOptions['sortType'] || DEFAULT_SORT_OPTION;
    const handleSortChange = (option) => {
        setFilterOptions(previous => Object.assign(previous, { 'sortType': option }))
    };
    return (
        <span className='filter-container'>
            <Select options={SORT_TYPE_OPTIONS} value={curSort} onChange={handleSortChange}/>
       </span>
    );
};
 

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

1. Можете ли вы предоставить минимальный, воспроизводимый пример? Я предполагаю, что вы не используете onChange prop внутри Select компонента.

2. @Yousaf Я пытался получить это в песочнице — codesandbox.io/s/react-select-default-value-forked-1ybdk?file =/… , надеюсь, это было бы полезно.

3. @Yousaf не могли бы вы немного подробнее объяснить, как не использовать onChange prop? Потому handleSortChange что это в основном метод onChange, который содержит setFilterOptions .

Ответ №1:

Пара проблем в вашем коде:

  1. Чтобы установить значение Select компонента по умолчанию, вы написали ненужный код. Вместо этого вы можете просто использовать defaultValue prop для установки значения Select компонента по умолчанию.
     <Select
       options={OPTIONS}
       defaultValue={OPTIONS[0]}
       onChange={handleSortChange}
    />
     
  2. Вы изменяете состояние напрямую. Object.assign(...) возвращает target объект. В вашем случае целевым объектом является предыдущее состояние.

    Вместо возврата нового объекта состояния вы изменяете состояние напрямую и возвращаете предыдущий объект состояния, что предотвращает повторный рендеринг.

    Используя spread-syntax , вы можете корректно обновить состояние, как показано ниже:

     const handleSortChange = (option) => {
       setFilterOptions({ ...filterOptions, sortType: option });
    };
     

Следующий код устраняет вышеупомянутую проблему в вашем компоненте:

 const SearchFilter = () => {
  const [filterOptions, setFilterOptions] = useState({});

  const handleSortChange = (option) => {
    setFilterOptions({ ...filterOptions, sortType: option });
  };

  return (
    <span className="filter-container">
      <Select
        options={OPTIONS}
        defaultValue={OPTIONS[0]}
        onChange={handleSortChange}
      />
    </span>
  );
};
 

Ответ №2:

Причина, по которой вы не видите изменений, заключается в том, что этот функциональный компонент будет повторно отображаться только тогда, когда увидит, что ваше состояние изменилось (на основе вашего сценария изолированной среды). В тот момент, когда вы используете Object.assign(previous, { 'sortType': option}) , вы меняете sortType свойство в объекте, но сам объект не изменяется, и поэтому функциональный компонент не видит изменений.

Мы можем решить эту проблему, используя либо Object.assign({}, previous, { 'sortType': option}) , который создаст НОВЫЙ объект с предыдущими атрибутами состояния и измененным типом сортировки (первый параметр Object.assign — это объект, в который будут скопированы следующие свойства объекта. если мы используем пустой объект, который является эквивалентом нового объекта) или мы можем использовать оператор распространения и заменить его на ({...sortType, 'sortType': option}) который также создаст новый объект, который функциональный компонент распознает как измененное значение состояния.

 const handleSortChange = (option) => {
    setFilterOptions(previous => Object.assign({}, previous, { 'sortType': option }))
};
 

или

 const handleSortChange = (option) => {
    setFilterOptions(previous => ({...previous, 'sortType': option})
};
 

Имейте в виду, что это мелкие копии объектов.

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

1. Большое спасибо, вы спасли мой день!! Я не знал, что Object.assign(previous, { 'sortType': option}) ссылка не изменяется…

2. Нет проблем, рад, что смог помочь!