React useState定义的变量无法实现非响应式值拷贝如何解决?
问题原因解析
你遇到的现象和对象拷贝方法无关,是React函数组件的渲染机制导致的:
- 每次调用
setNumber更新状态后,整个App函数组件都会重新执行 - 重渲染时你定义的3个拷贝变量都会重新创建,基于更新后的最新
number状态值做拷贝,所以自然会和最新状态保持一致 - 不存在你误以为的「拷贝变量和原状态有响应式绑定」的情况,只是每次重渲染时拷贝变量都被覆盖为了最新状态的副本,才会看起来同步更新
解决方案
你需要存储的是状态的初始值,所以要把初始值单独存储,避免每次重渲染被覆盖,有两种常用实现方式:
方案1:初始值为静态值时,提取为外部常量
把初始值提到组件外部定义,组件内所有用到初始值的地方都引用这个常量即可:
import { useState } from "react"; import "./styles.css"; // 静态初始值提到组件外部,不会随组件重渲染变化 const INITIAL_NUMBER = { val: 10 }; export default function App() { const [number, setNumber] = useState(INITIAL_NUMBER); // 基于初始常量拷贝,而不是基于当前状态拷贝 const numberAssign = Object.assign({}, INITIAL_NUMBER); const numberSpread = { ...INITIAL_NUMBER }; const numberJSON = JSON.parse(JSON.stringify(INITIAL_NUMBER)); const clicked = () => { setNumber({ val: number.val + 1 }); }; return ( <div className="App"> <button onClick={clicked}>Inc</button> <p>{number.val}</p> <p>{numberAssign.val}</p> <p>{numberSpread.val}</p> <p>{numberJSON.val}</p> </div> ); }
方案2:初始值为动态生成时,用useRef存储
如果初始值需要在组件渲染时动态生成(比如从props取值、计算得到),用useRef存储初始值,ref的值不会随组件重渲染更新:
import { useState, useRef } from "react"; import "./styles.css"; export default function App(props) { // 用useRef存初始值,只会在组件首次挂载时初始化一次 const initialNumberRef = useRef({ val: props.initialVal || 10 }); const [number, setNumber] = useState(initialNumberRef.current); const numberAssign = Object.assign({}, initialNumberRef.current); const numberSpread = { ...initialNumberRef.current }; const numberJSON = JSON.parse(JSON.stringify(initialNumberRef.current)); const clicked = () => { setNumber({ val: number.val + 1 }); }; return ( <div className="App"> <button onClick={clicked}>Inc</button> <p>{number.val}</p> <p>{numberAssign.val}</p> <p>{numberSpread.val}</p> <p>{numberJSON.val}</p> </div> ); }
内容的提问来源于stack exchange,提问作者Zbyněk Juřica
相关产品推荐
相关产品推荐

