You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

useState()与普通变量赋值的区别及React元素存state异常排查

一、useState() 和普通变量赋值的区别
  • 状态持久化:useState 创建的变量会在组件多次重新渲染之间保留值,普通变量每次组件渲染时都会被重新初始化,值无法留存。
  • 触发重渲染:调用 useState 对应的 setter 函数修改状态时,会触发组件重新渲染,让界面同步更新;普通变量的值改变不会触发任何 React 渲染流程,界面不会自动更新。
  • 绑定组件生命周期:useState 属于 React 的状态管理系统,会和组件的挂载、更新、卸载生命周期绑定;普通变量只是函数作用域内的局部变量,和 React 组件的生命周期完全无关。
二、为何示例中{name}和{name2}会出现差异

结合代码细节分析原因:

  1. 错误的 key 使用:你在渲染eltArr时用数组index作为组件的key。当点击删除按钮后,数组变成原数组从索引1开始的子集,此时React会根据key判断组件实例:原来索引1的元素现在对应索引0,React会复用原来索引0的SimpleItem组件实例,而非重新创建新实例。
  2. 组件 state 的初始化特性:SimpleItem里的name是用useState(props.name)初始化的,组件实例一旦创建,这个初始化只会执行一次。当组件被复用时,name的状态会保留第一次初始化的值,不会随着新的props.name更新。
  3. props 的实时性:而name2是直接取的当前props.name,每次组件渲染都会拿到最新的 props 值。

举个具体场景:

  • 初始渲染时,索引0的SimpleItem接收props.name='apple',name状态被初始化为apple,name2也是apple。
  • 删除第一个元素后,原索引1的SimpleItem(props.name='orange')现在对应索引0,React复用原来索引0的SimpleItem实例,这个实例的name状态还是apple,但props.name已经变成orange,所以name2是orange,两者就出现了差异。

另外补充:把React元素存在state里是React的反模式,正确的做法应该是把数据(比如['apple','orange',...])存在state中,然后在渲染时动态生成SimpleItem组件,这样就能避免这类问题。

附示例代码

const useState = React.useState;

function Example() {

const SimpleItem = (props) => {
    const [name, setName] = useState(props.name);
    const name2 = props.name;
    return <h4>{name} is the same as {name2}</h4>
}

const DEMO_ARR1 = [
    <SimpleItem name='apple' />,
    <SimpleItem name='orange'/>,
    <SimpleItem name='fish'/>,
    <SimpleItem name='cat'/>,
    <SimpleItem name='peel'/>,
    <SimpleItem name='eyeball'/>,
]

const Bad = () => {

    const [eltArr, setEltArr] = useState(DEMO_ARR1);

    return (
        <div>
                    
            {eltArr.map((item, i)=>{
                return <div key={i}>{item}</div>;
            })}

            <button key="button"
                onClick={() => {
                    setEltArr(eltArr.slice(1))
                }}
            >
                Delete index 0
            </button>
        </div>
    );
};

  return Bad();
}

ReactDOM.render(<Example />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

内容的提问来源于stack exchange,提问作者ResiumRegent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:53:09