React基础 第十九章(State状态保留与重置)

在React应用开发中,理解何时以及如何保留或重置组件的状态是至关重要的。

理解React的状态保留机制

在React中,组件的状态(state)是与组件实例紧密关联的。React通过组件在UI树中的位置来决定是否保留状态。当组件在渲染过程中保持在UI树的同一位置时,React会保留其状态。这意味着,如果你在两次渲染之间没有改变组件的位置或没有改变生成组件的关键属性(如key),那么组件的状态将被保留。

当你在React应用中渲染组件时,React会根据组件的位置来决定是否应该保留其内部状态。如果组件在UI树中的位置没有改变,React会认为它是同一个组件实例,并保留其状态。

技巧

  • 为了保证组件状态不被重置,你需要确保在不需要重置状态时,组件在UI树中的位置保持不变。

示例

jsx 复制代码
function App() {
  // Counter组件在UI树的相同位置
  return (
    <div>
      <Counter />
      <Counter />
    </div>
  );
}

在例子中,我们有一个App组件,它渲染了两个Counter组件。由于这两个Counter组件在每次渲染时都处于UI树的相同位置,React将会保留它们的状态。

注意事项

  • 如果你决定移除一个组件,那么它的状态也会随之销毁。当组件从UI树中移除后,如果再次将其添加回来,它将是一个全新的组件实例,带有初始状态。

正确代码

jsx 复制代码
// 显示或隐藏第二个计数器,但不改变第一个计数器的状态
function App() {
  const [showSecondCounter, setShowSecondCounter] = useState(true);
  return (
    <div>
      <Counter />
      {showSecondCounter && <Counter />}
    </div>
  );
}

在这个例子中,我们通过一个布尔状态showSecondCounter来控制第二个Counter组件的显示与隐藏。当我们切换这个状态时,第一个Counter组件的状态不会受到影响,因为它的位置没有改变。

错误代码

jsx 复制代码
// 错误:每次App组件渲染时,Counter组件都会被重新创建,导致状态重置
function App() {
  return (
    <div>
      <Counter key={Date.now()} />
    </div>
  );
}

在错误示例中,每次App组件渲染时,都会给Counter组件一个基于当前时间的新key。这导致React认为它是一个全新的组件实例,并且每次都会重置它的状态。

强制重置组件状态

有时候,我们需要在组件保持在同一位置时重置其状态。

技巧

  • 使用不同的key属性来强制React重置组件状态。

示例

jsx 复制代码
function Scoreboard() {
  const [player, setPlayer] = useState('PlayerA');

  return (
    <div>
      {/* 通过改变key来重置Counter组件的状态 */}
      {player === 'PlayerA' ? <Counter key="PlayerA" /> : <Counter key="PlayerB" />}
      <button onClick={() => setPlayer(player === 'PlayerA' ? 'PlayerB' : 'PlayerA')}>
        切换玩家
      </button>
    </div>
  );
}

注意事项

  • key属性不是全局唯一的,只在其父组件中标识唯一性。

正确代码

jsx 复制代码
// 使用key属性来区分不同的Counter实例
<Counter key="PlayerA" />
<Counter key="PlayerB" />

错误代码

jsx 复制代码
// 错误:没有使用key属性,React会认为是同一个Counter实例
<Counter />
<Counter />

避免无意中重置状态

在某些情况下,我们可能无意中重置了组件的状态,这通常是由于不恰当的组件结构或key的使用。

技巧

  • 避免在组件内部定义其他组件,这可能会导致状态意外重置。

示例

jsx 复制代码
// 正确:将MyTextField定义在MyComponent外部
function MyTextField() {
  const [text, setText] = useState('');
  return <input value={text} onChange={e => setText(e.target.value)} />;
}

function MyComponent() {
  const [counter, setCounter] = useState(0);
  return (
    <>
      <MyTextField />
      <button onClick={() => setCounter(counter + 1)}>
        点击了{counter}次
      </button>
    </>
  );
}

注意事项

  • 确保组件定义在其使用的最外层作用域中。

正确代码

jsx 复制代码
// MyTextField定义在MyComponent外部,避免了状态重置
function MyTextField() { /* ... */ }
function MyComponent() { /* ... */ }

错误代码

jsx 复制代码
// 错误:MyTextField定义在MyComponent内部,每次渲染都会重置状态
function MyComponent() {
  function MyTextField() { /* ... */ }
  // ...
}

通过遵循这些技巧和注意事项,你可以更好地控制React组件的状态保留和重置,从而创建出更稳定和可预测的用户界面。记住,合理地使用key属性和组件位置是管理状态的关键。

相关推荐
呦呦鹿鸣Rzh8 分钟前
Web前端开发
前端
会说法语的猪2 小时前
uniapp使用uni.navigateBack返回页面时携带参数到上个页面
前端·uni-app
古蓬莱掌管玉米的神10 小时前
vue3语法watch与watchEffect
前端·javascript
林涧泣10 小时前
【Uniapp-Vue3】uni-icons的安装和使用
前端·vue.js·uni-app
雾恋10 小时前
AI导航工具我开源了利用node爬取了几百条数据
前端·开源·github
拉一次撑死狗10 小时前
Vue基础(2)
前端·javascript·vue.js
祯民11 小时前
两年工作之余,我在清华大学出版社出版了一本 AI 应用书籍
前端·aigc
热情仔11 小时前
mock可视化&生成前端代码
前端
m0_7482463511 小时前
SpringBoot返回文件让前端下载的几种方式
前端·spring boot·后端
wjs040611 小时前
用css实现一个类似于elementUI中Loading组件有缺口的加载圆环
前端·css·elementui·css实现loading圆环