react条件渲染下state是否重置的问题

react两种条件渲染方式为什么效果不同

  1. return内内联条件判断的表达式(比如三元表达式,&&,||之类的)
  2. return外条件判断, 返回不同结果

代码示例codesandbox
也可以直接看下面的代码(推荐直接打开上面的sandbox查看效果)

第一种方式在点击next的时候会重置score这个state, 比如<Test>
第二种方式则不会重置score, 比如<Test2>
为什么?

export default function App() {
  return (
    <div className="App">
     <Test/>
     <Test2/>
    </div>
  );
}
function Test() {
  const [show, setShow] = useState(true);
  return (
    <div>
      {show && <Counter id={1} />}
      {show || <Counter id={2} />}
      <br />
      <label>
        <input
          type="checkbox"
          checked={show}
          onChange={(e) => {
            setShow(e.target.checked);
          }}
        />
        Next
      </label>
    </div>
  );
}
function Test2() {
  const [show, setShow] = useState(true);
  if (show) {
    return (
      <div>
        <Counter id={1} />
        <br />
        <label>
          <input
            type="checkbox"
            checked={show}
            onChange={(e) => {
              setShow(e.target.checked);
            }}
          />
          Next
        </label>
      </div>
    );
  }
  return (
    <div>
      <Counter id={2} />
      <br />
      <label>
        <input
          type="checkbox"
          checked={show}
          onChange={(e) => {
            setShow(e.target.checked);
          }}
        />
        Next
      </label>
    </div>
  );
}

function Counter({ id }) {
  const [score, setScore] = useState(0);
  return (
    <div style={{ display: "inline-block" }}>
      <h1>{score}</h1>
      <p>id:{id}</p>
      <button onClick={() => setScore(score + 1)}>Add one</button>
    </div>
  );
}
阅读 2.1k
1 个回答

这是节点有没有被复用而造成的问题
在你的例子Test中show变化前后的children数组分别是

[Counter1, true] ===> [false, Counter2]

其中boolean类型的值会被忽略,所以只有Counter组件会被渲染出来由于你没有给Counter元素指定显式的key所以在diff时React会用child在数组中的下标来作为他的key,所以Counter1的key为0,Counter2的key为1,所以更新前后节点并不能被复用,所以Counter1会被销毁,然后重新创建一个Counter2
在你的Test2例子中show变化前后的数组分别是
[Counter1] ===> [Counter2]
所以走的是更新流程Counter1的状态会被保留
要解决也很简单给Counter1Counter2一个显式的key就行,即将Test中的那部分代码改成即可

{show && <Counter key={1} id={1} />}
{show || <Counter key={1} id={2} />}

React的diff逻辑并不复杂,具体逻辑可以看这里

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏