Метод useState не сразу отражает изменения (решение, предложенное в Stackoverflow, не работает) - PullRequest
1 голос
/ 01 августа 2020

Каждый раз, когда я устанавливаю переменную с помощью useState, значение не отображается сразу. Здесь у меня есть useEffect, который вызывает computePriceSummary ();

useEffect(() => {
    computePriceSummary();
}, []);

computePriceSummary вызывает три функции, как показано:

const computePriceSummary = () => {
   computeSubtotal();
   computeTaxes();
   computeTotal();
};

Эти функции устанавливают переменные с помощью useState:

const computeTaxes = () => {
   let taxes = 0.05 * subtotal;
   setTaxes(taxes);
};

const computeTotal = () => {
   setTotal(taxes + subtotal);
 };

const computeSubtotal = () => {
   let subtotal = cart.products.reduce((acc, item) => {
     return (acc += item.product.price * item.quantity);
   }, 0);
   setSubtotal(subtotal);
 };

Значения, показанные в браузере:

Subtotal: $1200
Taxes: $0
Total: $0

Решение в Stackoverflow предлагает использовать useEffect для отслеживания переменных, что я и сделал:

useEffect(() => {
   console.log("Use effect to immediately set variables");
 }, [subtotal, taxes, total]);

Результат все тот же .

Ответы [ 2 ]

2 голосов
/ 01 августа 2020

Когда вы вызываете setSubtotal, переменная subtotal не обновляется мгновенно. Это означает, что ваши вызовы computeTaxes и computeTotal работают со старым значением.

Это будет нормально, если ваш эффект будет вызываться при каждом обновлении состояния или свойств, но это определение:

useEffect(() => {
    computePriceSummary();
}, []);

означает, что этот эффект вызывается только один раз . Чтобы исправить это, используйте что-то вроде этого:

useEffect(() => {
    computePriceSummary();
}, [subtotal, taxes, total]);

Компонент будет повторно визуализироваться при каждом изменении ваших переменных состояния, и, если они будут включены в зависимости эффекта, этот эффект будет перезапущен правильно.

Добавление второго эффекта (того, где вы используете console.log) не приведет к повторному запуску первого эффекта в вашем случае.

0 голосов
/ 01 августа 2020

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

useEffect(() => {
    computePriceSummary();
  }, [taxes, total, subtotal]);

Вы получите следующее предупреждение:

React Hook useEffect имеет недостающую зависимость: 'computePriceSummary'. Либо включите его, либо удалите массив зависимостей. (react-hooks / excustive-deps)

Вы можете увидеть это в действии в этой демо . Данные изменяются, но повторный рендеринг в этом компоненте не запускается.

Если вы включили computePriceSummary в массив зависимостей (всего 4), повторный рендеринг сработает.

Но есть новое предупреждение:

Функция computePriceSummary изменяет зависимости хука useEffect (в строке 37) при каждом рендеринге. Переместите его в обратный вызов useEffect. В качестве альтернативы можно заключить определение computePriceSummary в его собственный хук useCallback (). (react-hooks / excustive-deps).

Давайте исправим это, оборачивая функцию с помощью useCallback hook. useCallback заставляет саму функцию изменяться только при необходимости, имея собственный массив зависимостей.

const computePriceSummary = useCallback(() => {
    computeSubtotal();
    computeTaxes();
    computeTotal();
  }, []);

Опять же, вы получаете предупреждение о зависимости, теперь он просит включить все другие функции в качестве зависимостей:

React Hook useCallback не имеет зависимостей: computeSubtotal, computeTaxes и computeTotal. Либо включите их, либо удалите массив зависимостей. (react-hooks / excustive-deps)

И мы исправляем это, снова используя перехватчик useCallback со всеми другими функциями. Передача соответствующего состояния (того, которое используется внутри каждой функции) в их собственный массив зависимостей.

Это становится повторяющимся, не так ли? Возможно, вы захотите выполнить эти задачи в бэкэнде и использовать уменьшенные данные в React.

Здесь вы можете увидеть полную демонстрацию с эмулированной тележкой, которая обновляется при нажатии кнопки. Состояние настроено правильно, предупреждений о зависимостях нет, функционал работает нормально.

...