使用其他挂钩时usePrevious是否可靠?

时间:2020-06-10 23:16:10

标签: reactjs react-hooks

React Hooks documentation建议使用ref来访问state / props的先前值,甚至将其抽象到usePrevious自定义钩子中。

文档示例(使用按钮修改):

function Counter() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  return <div>
      <h1>Now: {count}, before: {prevCount}</h1>
      <button onClick={() => setCount(c => c + 1)}>Add</button>
    </div>
}

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

我在玩《 Counter》示例,并注意到如果您使用另一个不相关的钩子进行更新,它会中断。

export default function Counter() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  const [color, setColor] = useState("black");

  useEffect(() => {
    // This breaks the prev count counter: when displayed on screen, previous = count
    setColor(count % 2 ? "red" : "blue");
  }, [count]);

  return (
    <div>
      <h1>Now: {count}, before: {prevCount}</h1>
      <button style={{ color }} onClick={() => setCount(c => c + 1)}>
        Add
      </button>
    </div>
  );
}

...

似乎是由状态更新触发的重新渲染导致了此问题,因为在将示例设置为恒定值时,该示例按预期工作:

  ...

  useEffect(() => {
    // This works: When displayed, previous = count - 1
    setColor("black");
  }, [count]);

  ...

所以我的问题是:

  1. 为什么添加状态更新会导致此示例中断?
  2. 如果不相关的钩子导致它们更新,usePrevious /是否引用了可靠的解决方案?

Code Sandbox Link

1 个答案:

答案 0 :(得分:1)

先前的值是上次渲染时的值计数,而不是先前的值(如果有意义)。

由于颜色变化时渲染之间的计数没有改变,因此计数等于该渲染上的previousCount。

请改为使用另一个useState来跟踪lastCount并在调用setCount时对其进行更新。

const [lastCount, setLastCount] = useState(0);

 <button style={{ color }} onClick={() => {
let currentCount;
 setCount(c => {currentCount = c; return c + 1;});
setLastCount(currentCount);
}
}>
        Add
      </button>

在您的示例中,上一个值的有用之处在于您是否在询问“此渲染是否是由于计数更新引起的?”。如果count等于previousCount,则答案为否。