如何避免 React 钩子中 useEffect 中的 setState?

时间:2021-06-10 08:35:01

标签: reactjs react-hooks

我创建了一个简单的 calculator 并计算所有值(如果其中任何一个发生变化)。

但我遇到了 infinite loop 的问题。我知道这是由 setState 和触发 useEffect 然后再次 setState 引起的。

那么我怎样才能避免这种情况呢?

CodeSandBox

import "./styles.css";
import { useEffect, useState } from "react";

export default function App() {
  const [state, setState] = useState([
    { name: "label1", value: 0 },
    { name: "label2", value: 0 },
    { name: "label3", value: 0 }
  ]);
  const handleChange = (name) => (e) => {
    const value = e.target.value;
    const updated = state.map((item) => {
      if (item.name === name) {
        return { name, value };
      }
      return item;
    });
    setState(updated);
  };

  useEffect(() => {
    const calculate = () => {
      const base1 = 99999;
      const base2 = 0.3;
      const base3 = 0.078;
      const val1 = base1 * base2;
      const val2 = val1 / base1;
      const val3 = val1 + (base1 - val1) * base3;
      const updated = [
        { name: "label1", value: val1 },
        { name: "label2", value: val2 },
        { name: "label3", value: val3 }
      ];
      // const updated2 = state.map((item, index) => updated[index]);
      // setState(updated)
    };
    calculate();
  }, [state]);
  return (
    <div className="App">
      {state.map(({ name, value }, index) => (
        <p key={index}>
          {name}: <input value={value} onChange={handleChange(name)} />
        </p>
      ))}
    </div>
  );
}

2 个答案:

答案 0 :(得分:0)

您只需删除数组依赖项中的 state,因为它会在 state 更改时触发 useEffect

useEffect(() => {
    const calculate = () => {
      const base1 = 99999;
      const base2 = 0.3;
      const base3 = 0.078;
      const val1 = base1 * base2;
      const val2 = val1 / base1;
      const val3 = val1 + (base1 - val1) * base3;
      const updated = [
        { name: "label1", value: val1 },
        { name: "label2", value: val2 },
        { name: "label3", value: val3 }
      ];
      setState(preState => preState.map((item, index) => updated[index]))
    };
    calculate();
  }, []);

答案 1 :(得分:0)

您可以做的是在触发 setState 之前检查新值是否与当前状态不同:

const updated2 = state.map((item, index) => updated[index]);
if(updated2 !== state) setState(updated)

您也可以考虑从 useEffect 中提取 calculate() 并在您的 handleChange 中调用它