《你不知道的React》-状态重置与保留

330 阅读2分钟

小而美的系列教程,周末定时更新,后续会推出基于 React 从 0~1 开发的三方插件,如果有收获,记得给个点赞。

在文章开始前,先问大家一个问题,下面两种写法有差异吗?

const App = () => {
  const[isPlayerA, setIsPlayerA] = useState(true);
  const handleOnClick = () => setIsPlayerA(!isPlayerA);
   
  return (
    <>
      <button onClick={handleOnClick}>Next player</button>
      {isPlayerA ? (
        <Counter name="Taylor" />
      ) : (
        <Counter name="Sarah" />
      )}
    </>
  );
};
const App = () => {
  const[isPlayerA, setIsPlayerA] = useState(true);
  const handleOnClick = () => setIsPlayerA(!isPlayerA);

  return (
    <>
      <button onClick={handleOnClick}>Next player</button>
      {isPlayerA && <Counter name="Taylor" />}
      {!isPlayerA && <Counter name="Sarah" />}
    </>
  );
};

相信很多同学在日常开发中没太注意这类细节,又不是不能用!

image.png

两种其实是有差别的,当 Counter 内部有状态时,前者在切换 flag 时, Counter 内部状态会保持,而后者会重置状态。

const Counter = ({ name }: { name: string }) => {
  const [count, setCount] = useState(0);
  const handleOnClick = () => setCount(count + 1);

  return (
    <div>
      <p>球员:{name}</p>
      <p>成绩:{count}</p>
      <button onClick={handleOnClick}>+1</button>
    </div>
  );
};

三元表达式:

p1.gif


&& 符:

p2.gif

看完表现,大家能猜到原因吗?

对于前者,不论 flag 是 true 还是 false,由于 Couter 在 UI Tree 里面的位置是一致的(推荐大家去了解下 UI Tree,和你想象的也许有差别),只有 props name 更新了,React 会认为它没有改变,所以状态被保留。

对于后者,你会不会也认为他俩在 UI Tree 里面是相同的?其实不是的,当 flag: true 的时候,并不会渲染Sarah,反之不会渲染Taylor;状态切换的时候存在销毁过程,销毁是会清除状态的。

image.png

如果我们既想用前者,又不想保留状态,该如何实现呢?方法比较多,我们介绍两种比较常见的。

  1. key
  2. 不同位置

key: 大家都不陌生,直接看示例

 {isPlayerA ? (
    <Counter key="Taylor" name="Taylor" />
  ) : (
    <Counter key="Sarah" name="Sarah" />
  )}

由于 key 不相同, React 会认为是 2 个不同的组件,切换的时候也会触发销毁,达到 reset state 的效果。

不同位置:我们可以用 div 和 article 包裹一下组件,由于 React 在做 diff 时发现元素类型不同,会将所有子元素直接移除,重新渲染,也可以达到 reset State 的效果。

  {isPlayerA ? (
    <div>
      <Counter name="Taylor" />
    </div>
  ) : (
    <article>
      <Counter key="Sarah" name="Sarah" />
    </article>
  )}

如果你意犹未尽:beta.reactjs.org/learn/prese…