В useEffect отсутствует зависимость, но когда я ее добавляю, я получаю сообщение об ошибке «Превышена максимальная глубина обновления» - PullRequest
3 голосов
/ 06 января 2020

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

Все работает так, как я планировал, массив сортируется при монтировании компонента, а затем по нажатию кнопки.

Однако я получаю сообщение об ошибке от linter о том, что массив значений должен быть объявлен как зависимость в хуке useEffect. Если я это сделаю, я получу ошибку «Максимальная глубина обновления превышена». Я не уверен, что делать, и я был бы признателен за любую помощь!

Ссылка на код

Спасибо за взгляд, это действительно много значит для меня!

Ответы [ 3 ]

1 голос
/ 06 января 2020

В идеале, вы бы добавили некоторое условие / проверку, чтобы увидеть, имеет ли values то значение, которое вы хотите. Поскольку setValues, кажется, вызывается при каждом рендеринге, который вызывает повторный рендеринг, умноженный на бесконечность.

Потенциально, используя что-то вроде Loda sh 's isEqual в сочетании с Loda sh s orderBy сделает этот трюк (потому что sort будет видоизменять исходный массив).

  const [ascValue, setAscValue] = useState(true);
  const [values, setValues] = useState([
    { id: 10 },
    { id: 5 },
    { id: 12 },
    { id: 1 },
    { id: 2 },
    { id: 900 },
    { id: 602 }
  ]);

  useEffect(() => {
    function sortValues() {
      const sorter = ascValue ? "asc" : "desc";
      if (!_.isEqual(values, _.orderBy(values, ["id"], [sorter]))) {
        console.log("logged");
        setValues(() => _.orderBy(values, ["id"], [sorter]));
      }
    }

    sortValues();
  }, [ascValue, values]);

Дело в том, что useEffect не должно устанавливать состояние каждый при каждом рендеринге по умолчанию (он может завершить рендеринг, когда пользователь запускает действие).

Форк вашего CodeSandbox, чтобы продемонстрировать , что побочный эффект должен обновлять состояние компонентов только в случае выполнения условия.

1 голос
/ 06 января 2020

Это не удивительно - когда вы добавляете список значений в массив зависимостей, useEffect будет выполняться при каждом изменении списка значений - что приводит к бесконечному l oop :)

В соответствии с предыдущий ответ @norbitrial, сокрытие ошибки не решит проблему, потому что все зависимости от области видимости ДОЛЖНЫ быть объявлены в массиве зависимостей, избегая этого, что может привести к непредвиденным поведениям.

Я бы рекомендовал рассмотреть использование useReducer в этой ситуации. Это приведет к тому, что логи c модификаций массива зависимостей могут быть перемещены из области действия useEffect hooks - и вы не будете вынуждены присоединять его как зависимость useEffect.

1 голос
/ 06 января 2020

Я не вижу проблем с вашим кодом. Я просто проигнорировал бы предупреждение, добавив // eslint-disable-next-line react-hooks/exhaustive-deps в следующем виде:

useEffect(() => {
    function sortValues() {
      let sorted;
      const array = [...values];
      if (ascValue) {
        sorted = array.sort((a, b) => a - b);
      } else {
        sorted = array.sort((a, b) => b - a);
      }

      setValues(sorted);
    }

    sortValues();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ascValue]);

Возможно одно сокращение на sortValues():

function sortValues() {
    const compare = ascValue ? (a, b) => a - b : (a, b) => b - a;
    setValues([...values].sort(compare));
}

Надеюсь, это поможет!

...