@tostershmoster

Почему в стейт попадает предыдущее состояние? Как правильно его обновлять?

setAllTODOS(sortedTodos); // значение меняется со второго раза
setAllTODOS((prevTodos) => sortedTodos); // и так тоже


const SortConst = ['last updated', 'finish date', 'responsible'] as const;
type TSortConst = (typeof SortConst)[number];

const TODOList = observer(() => {
  const { todoStore, userStore } = useContext(StoreContext);
  const [allTODOS, setAllTODOS] = useState<ITodo[]>([]);
  const [sort, setSort] = useState<TSortConst | string>('last updated');

  const sortTodos = (todos: ITodo[], sortType: TSortConst): ITodo[] => {
    console.log(sortType);

    switch (sortType) {
      case 'finish date':
        return todos.sort((a, b) => {
          console.log('finish date');
          const dateA = new Date(a.finishDate);
          const dateB = new Date(b.finishDate);
          return dateA.getTime() - dateB.getTime();
        });
      case 'responsible':
        console.log('responsible');
        return todos.sort((a, b) => {
          console.log('responsible');
          return Number(a.responsible) - Number(b.responsible);
        });
      default:
        // last updated
        return todos.sort((a, b) => {
          console.log('last updated');
          const dateA = new Date(a.updatedAt);
          const dateB = new Date(b.updatedAt);
          return dateB.getTime() - dateA.getTime();
        });
    }
  };

  const getUserTodos = useCallback(
    (userId: number): ITodo[] =>
      todoStore.todos.filter((todo) => Number(todo.responsible) === userId),
    [todoStore.todos],
  );

  useEffect(() => {
    todoStore.fetchAllTodos();
  }, [todoStore]);

  useEffect(() => {
    console.log('change');

    if (userStore.isAuth) {
      if (userStore.user?.role === 'ADMIN') {
        const sortedTodos = sortTodos(todoStore.todos, sort as TSortConst);
        console.log(sortedTodos); // сортировка происходит
        // setAllTODOS(sortedTodos); // значение меняется со второго раза
        setAllTODOS((prevTodos) => sortedTodos); // и так тоже значение меняется со второго раза
      } else if (userStore.user?.role === 'USER') {
        const userTodos = getUserTodos(userStore.user?.id);

        const sortedTodos = sortTodos(userTodos, sort as TSortConst);
        console.log(sortedTodos); // сортировка происходит
        // setAllTODOS(sortedTodos); // значение меняется со второго раза
        setAllTODOS((prevTodos) => sortedTodos); // и так тоже значение меняется со второго раза
      }
    }
  }, [
    getUserTodos,
    todoStore.todos,
    userStore.isAuth,
    userStore.user?.id,
    userStore.user?.role,
    sort,
  ]);

  return (
    <div>
      {todoStore.isLoading ? (
        <div
          className="d-flex justify-content-center align-items-center"
          style={{ height: window.innerHeight }}
        >
          <Spinner animation="border" role="status" />
        </div>
      ) : (
        <Row className="d-flex mb-5">
          {!userStore.isAuth ? (
            <div
              className="d-flex justify-content-center align-items-center"
              style={{ height: window.innerHeight }}
            >
              Login To See Your TODOS
            </div>
          ) : (
            <>
              {allTODOS.length > 0 && (
                <RDropdown
                  variable={sort}
                  setVariable={setSort}
                  toggleText="Sort by"
                  itemsArray={[...SortConst]}
                />
              )}
              {allTODOS.map((todo) => (
                <Col key={todo.id} sm={12} lg={12}>
                  <TODOItem todo={todo} />
                </Col>
              ))}
            </>
          )}
        </Row>
      )}
    </div>
  );
});

export default TODOList;
  • Вопрос задан
  • 101 просмотр
Решения вопроса 1
@HealSpirit
sort() сохраняет ссылку на старый массив. toSorted() возвращает новую ссылку на массив. Только новая ссылка позволяет понять реакту, что надо ререндерить компонент.
Использовать надо toSorted() или
setAllTODOS([...sortedTodos]);
setAllTODOS((prevTodos) => [...sortedTodos]);
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы