Не вызывает ли useState повторный переход при работе с состояниями объекта?

#reactjs #firebase #render #react-hooks

#reactjs #firebase #визуализация #реагирующие хуки

Вопрос:

У меня есть firebase проект с a firestore database document , который выглядит следующим образом.

 document-id => 
    item1 => {detail: "value", title: "value", image: "value}
    item2 => {detail: "value", title: "value", image: "value}
    ...
  

Мой React component рендеринг выглядит примерно так:

 const [data, setData] = useState({});

useEffect(() => {
  firebase.getDocument("path-to-document").then(section => {
    if (section) {
      setPanels(section.data());
    }
  });
}, []);

const handleChange = (id, data) => {
  const payload = data;
  payload[id] = { ...panels[id], ...data };
  setData(payload);
}

return (<div>
  {Object.keys(data).map((key) => <Card
    data={data[key]}
    onChange={handleChange} />)}
</div>);
  

Я удалил из этого дополнительный код, но Card компонент simple устанавливает макет для отдельных объектов. При изменении он вызывает handleChange функцию правильно, и data State она правильно обновляется до новых значений (вызов console.log(data) после setData вызова метода показывает это). Однако component это не reRender происходит с новыми значениями для data .

Есть ли какой-нибудь способ принудительно выполнить повторный запуск компонента? Я нашел в другом месте в Интернете, что React «отключается» от повторного запроса, если setData вызывается с теми же данными, что и в настоящее время, т.Е. Никаких фактических изменений не будет сделано.

Или, наоборот, есть ли другой способ справиться с этим взаимодействием и позволить Card компоненту обрабатывать сохранение данных?

Спасибо.

Ответ №1:

Попробуйте установить копию вашей полезной нагрузки: {...payload} :

 const handleChange = (id, data) => {
  const payload = data;
  payload[id] = { ...panels[id], ...data };
  setData({...payload});
}
  

Поскольку вы не меняете состояние, ваше приложение не реагирует и не выполняет повторные запросы.

Ознакомьтесь с функциональными обновлениями в документах React.

 const handleChange = (id, data) => {
  const payload = data;
  payload[id] = { ...panels[id], ...data };
  setData(prevPayload => {
      console.log(prevPayload === payload)            // true
      return payload                                  // No Re-Render

      // console.log(prevPayload === { ... payload }) // false
      // return { ... payload }                       // Re-render
  );
}
  

Изучите этот пример в codesandbox.

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

1. Это правильно, но вы должны объяснить, почему это так.