首页 > 解决方案 > 使用其他钩子时 usePrevious 可靠吗?

问题描述

React Hooks 文档建议使用 refs 来访问 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 / refs 是一个可靠的解决方案吗?

代码沙盒链接

标签: reactjsreact-hooks

解决方案


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

由于颜色变化时渲染之间的计数不会更改,因此计数等于该渲染上的 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 则答案是否定的。


推荐阅读