Обновление поля вложенного объекта без повторного отображения

#reactjs #react-hooks #use-state

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

Вопрос:

Я столкнулся с проблемой, из-за которой react не распознает изменения, которые я внес в отношении правильности использования вложенного объекта useState, и, следовательно, не выполняет повторный рендеринг компонента.

В данном случае при разрешении пользователя.данные и разрешения.данные. Я не в первый раз сталкиваюсь с такой проблемой, что не так с моим кодом?

Вот пример:

 const [userPermission, setUserPermission] = useState({
    loading: false,
    data: [],
    selectedRows: [],
    selectedRowKeys: {},
  });
const [permission, setPermission] = useState({
    loading: false,
    data: [],
    pagination: {
      current: 1,
      pageSize: 10,
      total: 0,
      position: ['topRight' as const],
    },
    selectedRows: [],
    selectedRowKeys: {},
  });


 async function handleAddPermission(): Promise<any> {
    if (context === 'menus') {
      // const params = {
      //   menusIds: permission.selectedRowKeys,
      //   funcsIds: [],
      // };

     // const response = await addPermission(userId, params);

      const currentUserPermissions = { ...userPermission };
      const currentPermissions = { ...permission };

      const concat = currentUserPermissions.data.concat(
        permission.selectedRows,
      );

      // data upadate
      setUserPermission({ ...userPermission, data: concat });

      permission.selectedRows.map((selected: any) => {
        const findSelectedIndex = permission.data.findIndex(
          (data: any) => data.id === selected.id,
        );
        if (findSelectedIndex !== -1) {
          currentPermissions.data.splice(findSelectedIndex, 1);
        }
      });

      // data doesn't upadate
      setPermission(currentPermissions);
    }
  }

return (
    <>
      <Collapse accordion defaultActiveKey="1">
        <Panel header={userPermissionTitle} key="1">
          <Table
            dataSource={userPermission.data}
            columns={userPermissionColumns}
            pagination={false}
            loading={userPermission.loading}
            sortDirections={['ascend', 'descend', 'ascend']}
            // rowKey={record => record.id}
          />
        </Panel>
        <Panel header={permissionTitle} key="2">
          <SelectedContainer>
            <p> {`${permission.selectedRows.length} selecionados`} </p>
            <Button onClick={() => handleAddPermission()} size="small">
              Adicionar ao usuário
            </Button>
          </SelectedContainer>
          <Table
            dataSource={permission.data}
            columns={permissionColumns}
            onChange={handlePermissionTable}
            pagination={permission.pagination}
            loading={permission.loading}
            sortDirections={['ascend', 'descend', 'ascend']}
            rowSelection={{
              ...PermissionsRowSelection,
            }}
            rowKey={(record: any) => record.id}
          />
        </Panel>
      </Collapse>
    </>
  );
  

Ответ №1:

Попробуйте поместить хук useEffect вокруг UserPermission.данные и посмотрите, попадете ли вы после изменения состояния. Если это произойдет, то react распознает изменение состояния. Вместо использования useState вы можете использовать useReducer.

useReducer обычно предпочтительнее useState, когда у вас сложная логика состояния, которая включает в себя несколько вложенных значений или когда следующее состояние зависит от предыдущего. https://reactjs.org/docs/hooks-reference.html#usereducer

Ответ №2:

Вы можете обновлять вложенные объекты, подобные этому, внутри вашего обработчика ввода / обновления. Оператор распространения создает только мелкие копии. однако это создает клон нашего объекта, сохраняющий вложенные поля.

 // InitialValue is your current state
const initialValue = {answer: {
    highest:42,
    flag:true
}};


let newValue = JSON.stringify(initialValue);
newValue = JSON.parse(newValue)
newValue.answer.flag = false;

//You can provide this new value to your setState()
console.log(newValue)