Как обновить состояние, которое зависит от другого состояния, с помощью React Hooks - PullRequest
2 голосов
/ 03 апреля 2019

Итак, у меня есть этот пользовательский хук:

import sortBy from 'lodash/fp/sortBy';
import { useState, useEffect } from 'react';

/**
 * Custom effect that enables data sorting.
 * It is triggered every time when sort order or data has changed.
 *
 * @param {*} initialSort
 * @param {*} data
 */
function useSorting(initialSort, data) {
  const [sortOrder, setSortOrder] = useState(initialSort);
  const [sortedData, setSortedData] = useState([]);
  useEffect(() => setSortedData(sortBy(sortOrder, data)), [data, sortOrder]);

  return [sortedData, sortOrder, setSortOrder];
}

export default useSorting;

Он принимает данные для сортировки и порядок сортировки.Каждый раз, когда порядок сортировки изменяется с помощью setSortOrder или предоставляется новый data, он должен выполнить сортировку и обновить sortedData.

Это правильный путь?Я имею в виду, иметь useEffect, который слушает изменения в [data, sortOrder]?

Без перехватчиков React я бы использовал componentDidUpdate и вручную проверял, был ли изменен sortOrder или data, и делал бы this.setState с новым sortedData.Похоже, что делает то же самое

1 Ответ

2 голосов
/ 03 апреля 2019

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

1 - вы попадаете в код вашего хука

2 - вы перехватываете setSortedData для обновления своего sortedData состояния

3 - он возвращает устаревший sortedData вашему компоненту (потому что он был прочитан из useState перед изменением)

4 - вызов setSortedData запускается, изменяет данные в состоянии, запускает новый рендеринг вашего компонента, который снова будет использовать ваш хук, и хук предоставит правильную версию sortedData.

В двух словах, у вас есть один дополнительный рендер.Если вы хотите предотвратить это, вы можете использовать useMemo, например, так:

function useSorting(initialSort, data) {
  const [sortOrder, setSortOrder] = useState(initialSort);
  const sortedData = useMemo(() => sortBy(sortOrder, data), [data, sortOrder]);

  return [sortedData, sortOrder, setSortOrder];
}

Ваш компонент сразу получит отсортированные данные без необходимости проходить через дополнительный цикл рендеринга, и у вас все еще естьпреимущества вызова функции сортировки только в случае изменения соответствующей информации (data, sortOrder).

...