当前位置: 首页 > news >正文

React 16

useState 内部核心逻辑的简化模拟和可视化展示

export function getFinalState(baseState, queue) {let finalState = baseState;for (let update of queue) {if (typeof update === 'function') {// 调用更新函数finalState = update(finalState);} else {// 替换下一个 statefinalState = update;}}return finalState;
}
import { getFinalState } from './processQueue.js';function increment(n) {return n + 1;
}
increment.toString = () => 'n => n+1';export default function App() {return (<><TestCasebaseState={0}queue={[1, 1, 1]}expected={1}/><hr /><TestCasebaseState={0}queue={[increment,increment,increment]}expected={3}/><hr /><TestCasebaseState={0}queue={[5,increment,]}expected={6}/><hr /><TestCasebaseState={0}queue={[5,increment,42,]}expected={42}/></>);
}function TestCase({baseState,queue,expected
}) {const actual = getFinalState(baseState, queue);return (<><p>初始 state:<b>{baseState}</b></p><p>队列:<b>[{queue.join(', ')}]</b></p><p>预期结果:<b>{expected}</b></p><p style={{color: actual === expected ?'green' :'red'}}>你的结果:<b>{actual}</b>{' '}({actual === expected ?'正确' :'错误'})</p></>);
}

这两段代码本质上是对 useState 内部核心逻辑的简化模拟和可视化展示,目的是揭开它的 “黑盒” 面纱。

具体来说:

  1. getFinalState 函数模拟了 useState 处理更新队列的核心规则 —— 如何依次处理直接值更新(如 setX(5))和函数式更新(如 setX(n => n+1)),并计算出最终状态。
  2. 测试用例则通过不同场景(纯直接值、纯函数、混合类型)验证了这种规则,对应到实际开发中 useState 处理多次状态更新的效果。

当然,真实的 useState 内部逻辑要复杂得多(比如需要关联组件生命周期、触发重新渲染、处理并发更新等),但这两段代码抓住了最核心的 “状态更新队列处理逻辑”,让我们能直观理解 useState 为什么能正确处理连续更新、函数式更新的作用等关键问题。

可以说,它们是 useState 核心原理的 “极简教学版”。

React 状态管理中 “不可变数据(Immutability)” 原则

1. 为什么直接修改 state 对象有问题?

在 React 中,state 的更新依赖于 “引用变化” 来识别状态更新。如果直接修改 state 中已有的对象(如 position.x = e.clientX),会导致:

  • React 无法正确检测状态变化:因为对象的引用(内存地址)没有改变,React 的更新机制可能无法识别到状态更新,进而不会触发组件重新渲染。
  • 破坏 “时间旅行” 等调试特性:React 依赖状态的不可变性来实现历史状态回溯(如 Redux 的时间旅行调试),直接修改会导致这些特性失效。

2. 为什么创建新对象再更新 state 是正确的?

当我们创建一个新对象(如 const nextPosition = {} 再赋值属性),或者直接传入新的对象字面量(setPosition({x: e.clientX, y: e.clientY}))时:

  • 引用发生了变化:新对象的内存地址与原 state 对象不同,React 能明确识别到状态更新,从而触发组件重新渲染。
  • 遵循了不可变数据原则:原 state 对象始终保持不变,所有状态更新都是通过 “创建新数据” 来实现的,这是 React 生态(包括 hooks、Redux 等)推荐的最佳实践。

3. 延伸:复杂对象的不可变更新

如果 state 是更复杂的嵌套对象(如 { user: { name: 'xxx', age: 18 } }),更新时需要深层创建新对象,避免修改原有嵌套结构。例如:

// 错误:直接修改嵌套对象
setState(prev => {prev.user.age = 19; return prev; 
});// 正确:创建新的嵌套对象
setState(prev => ({...prev, user: { ...prev.user, age: 19 } 
}));

总结:React 中更新状态时,必须通过创建新对象 / 新数组来保证数据的不可变性,这样才能让 React 正确检测状态变化并维持生态工具的正常运行。

3 state 不可变

一、“不可变数据” 的概念本质

“不可变” 意味着 “一旦创建,就不能直接修改其内部数据;若要更新,必须创建一个全新的副本”

以生活场景类比:你有一张写着 “汉堡” 的明信片(原 state),如果要把它改成 “新德里”,不能直接在原明信片上涂画(直接修改 state),而应该重新写一张新的明信片(创建新对象),再替换掉原来的。

二、React 中 “state 不可变” 的技术原理

React 是通过“引用对比”来判断 state 是否变化的。

  • 每个对象在内存中都有一个唯一的“引用地址”(类似身份证号)。
  • 若直接修改 state 对象的属性(如 person.artwork.city = 'New Delhi'),对象的引用地址没有变化,React 会认为 “状态没更新”,进而不会触发组件重新渲染。
  • 只有当 setState(或 useState 的 setter 函数)接收到全新的对象引用时,React 才会识别到状态变化,触发重新渲染。

三、嵌套对象场景的 “不可变更新” 实践

当 state 是嵌套对象(如 person 包含 artwork 子对象)时,更新需要“深层创建新对象”,保证每一层的引用都发生变化。

以示例中的 person.artwork.city 更新为例,分步解析:

步骤 1:创建新的 artwork 子对象

使用对象扩展运算符 ... 复制原 artwork 的所有属性,再覆盖 city 属性:

const nextArtwork = { ...person.artwork, city: 'New Delhi' };

这样就得到了一个新的 artwork 对象(引用地址与原 person.artwork 不同)。

步骤 2:创建新的 person 对象

同样用扩展运算符复制原 person 的所有属性,再将 artwork 替换为刚创建的 nextArtwork

const nextPerson = { ...person, artwork: nextArtwork };

此时 nextPerson 是一个全新的 person 对象(引用地址与原 person 不同)。

步骤 3:用 setter 函数更新状态
setPerson(nextPerson);

由于 nextPerson 是新引用,React 能识别到状态变化,触发组件重新渲染。

四、“不可变更新” 的简化写法(合并步骤)

实际开发中,也可以将步骤合并为一行代码,逻辑完全等价:

setPerson(prev => ({...prev, artwork: { ...prev.artwork, city: 'New Delhi' } 
}));

这里使用了 useState 的函数式更新prev 表示上一次的 state),进一步保证了状态的不可变性。

五、“state 不可变” 的实践意义

  1. 保证 React 渲染的正确性:只有通过新引用,React 才能准确识别状态变化,避免 “状态更新了但组件没渲染” 的 bug。
  2. 支持时间旅行调试:如 Redux 的 “历史状态回溯” 功能,依赖状态的不可变性来保存每一次的状态快照。
  3. 避免副作用:直接修改 state 可能导致多个组件共享同一份数据时出现意外同步,不可变更新能让数据流转更可预测。

总结来说,“state 不可变” 是 React 状态管理的核心契约—— 它不是限制,而是为了让组件渲染、状态调试、数据流转更可靠的设计原则。掌握 “创建新对象 / 新数组来更新状态” 的技巧,是编写健壮 React 应用的关键基础。

4  Immer 库在 React 状态更新中的作用

一、Immer 解决的核心痛点

在 React 中,当 state 是多层嵌套对象时,手动实现 “不可变更新” 会非常繁琐(需要逐层创建新对象,如前面例子中的 nextArtworknextPerson)。Immer 的出现就是为了让开发者用 “直接修改对象” 的简洁语法,自动实现 “不可变更新”,兼顾开发效率和状态管理的规范性。

二、Immer 的核心原理:“draft 代理 + 自动不可变处理”

Immer 的工作流程可以总结为以下三步:

  1. 创建 draft 代理:当你调用 Immer 的更新函数(如 updatePerson)时,Immer 会创建一个 draft 对象 —— 它是原 state 的 “代理副本”。
  2. 允许 “看似直接的修改”:你可以像修改普通对象一样修改 draft(如 draft.artwork.city = 'Lagos'),但这只是 “表面操作”。
  3. 自动生成不可变新对象:Immer 会追踪 draft 的修改,在内部自动创建全新的、不可变的状态副本,最后将这个新副本作为状态更新的结果。

三、Immer 在 React 中的使用逻辑(结合示例)

以你提供的代码为例:

updatePerson(draft => {draft.artwork.city = 'Lagos';
});
  • updatePerson 是 Immer 生成的 “状态更新函数”(通常由 useImmer 或 produce 方法创建)。
  • draft 是 Immer 提供的 “可修改代理”,它的结构和原 state 完全一致。
  • 当你修改 draft.artwork.city 时,Immer 并不会直接修改原 state,而是在幕后创建新的 artwork 对象和新的 person 对象,最终保证状态更新的 “不可变性”。

四、Immer 的优势总结

  1. 代码简洁性:无需手动写多层扩展运算符(...)来创建新对象,大幅减少嵌套更新的 boilerplate 代码。
  2. 认知负担低:开发者可以用 “直觉式的对象修改语法” 编写逻辑,无需时刻关注 “不可变更新” 的底层细节。
  3. 保证状态安全:虽然写法像 “直接修改”,但底层依然严格遵循 “不可变” 原则,不会出现 React 状态更新的异常问题。

简言之,Immer 是 React 生态中 “简化不可变状态更新” 的利器 —— 它让开发者既能享受 “直接修改对象” 的便捷,又能严格遵守 React “状态不可变” 的核心契约。

5 “不可变数据” 原则及实践的核心总结

1. 将 React 中所有的 state 都视为不可直接修改的

React 对 state 的更新依赖“引用变化”来识别状态变更。直接修改 state 会导致 React 无法正确检测变化、组件不重渲染,还会破坏时间旅行调试等特性。因此,所有 state 都应被视为 “只读”,更新时必须创建新数据。

2. 当你在 state 中存放对象时,直接修改对象并不会触发重渲染,并会改变前一次渲染 “快照” 中 state 的值

  • 不触发重渲染:因为对象的引用地址未改变,React 认为状态没有更新,所以不会触发组件重新渲染。
  • 污染历史快照:React 渲染过程中会保留状态的 “快照” 用于对比和调试,直接修改会让历史快照被篡改,导致调试时状态追溯出错(比如 React DevTools 中查看历史状态时出现异常)。

3. 不要直接修改一个对象,而要为它创建一个新版本,并通过把 state 设置成这个新版本来触发重新渲染

这是 “不可变更新” 的核心动作:

  • 若原 state 是 { name: "Alice" },更新时需创建新对象 { ...oldState, name: "Bob" }(通过对象展开语法或 Object.assign 等方式)。
  • 新对象的引用地址与原对象不同,React 能识别到变化,从而触发组件重渲染。

4. 你可以使用这样的 {...obj, something: 'newValue'} 对象展开语法来创建对象的拷贝

对象展开语法(...)是创建对象浅拷贝的便捷方式:

const oldObj = { a: 1, b: { c: 2 } };
const newObj = { ...oldObj, a: 3 }; 
// newObj: { a: 3, b: { c: 2 } } —— a 被更新,b 还是原引用

它能快速创建对象的 “一层新拷贝”,是不可变更新的基础工具之一。

5. 对象的展开语法是浅层的:它的复制深度只有一层

展开语法只对对象的 “第一层级属性”做拷贝,嵌套的子对象依然是原引用。以上面的 newObj 为例,newObj.b 依然指向 oldObj.b 的内存地址 —— 如果修改 newObj.b.c,本质还是在修改原对象的嵌套属性,会引发不可变更新的问题。

6. 想要更新嵌套对象,你需要从你更新的位置开始自底向上为每一层都创建新的拷贝

对于嵌套对象(如 state = { user: { info: { age: 18 } } }),更新时需从最内层开始,逐层创建新对象

// 错误:只拷贝了最外层,内层还是原引用
setState({ ...state, user: { ...state.user, info: { ...state.user.info, age: 19 } } });// 正确:自底向上逐层创建新拷贝
const newInfo = { ...state.user.info, age: 19 };
const newUser = { ...state.user, info: newInfo };
setState({ ...state, user: newUser });

这样才能保证每一层的引用都发生变化,让 React 正确识别状态更新。

7. 想要减少重复的拷贝代码,可以使用 Immer

手动处理多层嵌套对象的不可变更新会产生大量重复代码(如层层展开、创建中间变量)。Immer 库通过 “draft 代理” 机制,允许开发者用“直接修改对象” 的简洁语法编写逻辑,底层自动完成 “逐层创建新拷贝” 的不可变处理,大幅简化代码复杂度(如前面示例中 draft.artwork.city = 'Lagos' 式的写法)。

总结来说,这七条摘要完整覆盖了 React 不可变状态管理的原则、问题、解决方案和工具选型,是理解 React 状态更新机制的关键指南。

-----

很🙄💅mean 的解释版本

拜托🙄💅,臭贝贝你是不是眼睛也不好使啊?说了要翻白眼指甲油表情包,结果还漏了提,合着我之前叭叭半天,你连重点都抓不住?

React state 不可变这事儿,跟你涂指甲油似的,得按规矩来啊!🙄💅 臭贝贝你总不能直接往旧指甲上叠新色吧?不得先清干净、打底,一步步来才好看?state 也一样,直接改就是瞎折腾,React 认不出来,跟你涂坏指甲油似的,最后丑的还是自己!

嵌套对象更新要逐层建新拷贝,就像你做美甲要分层上色,少一层都不精致,臭贝贝你连这破道理都不懂?🙄💅 Immer 就是美甲工具,给你省了分层的麻烦,直接用 draft 改就行,还非得让我掰开揉碎了说,真是个让人头大的臭贝贝!

要不要我再给你整个 “不可变美甲教程”,一步一步教你怎么 “涂” state 啊,臭贝贝?🙄💅

-----

6 React 状态更新修复学习笔记

一、问题代码(原代码)

import { useState } from 'react';export default function Scoreboard() {const [player, setPlayer] = useState({firstName: 'Ranjani',lastName: 'Shettar',score: 10,});// 问题1:直接修改state原对象,不触发重渲染function handlePlusClick() {player.score++; // 直接修改原对象,违反不可变原则}// 正确:使用展开运算符保留保留旧数据function handleFirstNameChange(e) {setPlayer({...player,firstName: e.target.value,});}// 问题2:更新时未保留旧数据,导致其他字段丢失function handleLastNameChange(e) {setPlayer({lastName: e.target.value // 只更新lastName,丢失firstName和score});}return (<><label>Score: <b>{player.score}</b>{' '}<button onClick={handlePlusClick}>+1</button></label><label>First name:<input value={player.firstName} onChange={handleFirstNameChange} /></label><label>Last name:<input value={player.lastName} onChange={handleLastNameChange} /></label></>);
}

二、修复后代码

import { useState } from 'react';export default function Scoreboard() {const [player, setPlayer] = useState({firstName: 'Ranjani',lastName: 'Shettar',score: 10,});// 修复1:通过setPlayer创建新对象,保留旧数据并更新scorefunction handlePlusClick() {setPlayer({...player, // 复制原有所有属性score: player.score + 1 // 计算新分数(避免直接修改)});}// 保持正确:展开运算符保留旧数据function handleFirstNameChange(e) {setPlayer({...player,firstName: e.target.value,});}// 修复2:添加展开运算符,保留旧数据function handleLastNameChange(e) {setPlayer({...player, // 复制原有所有属性(避免丢失firstName和score)lastName: e.target.value});}return (<><label>Score: <b>{player.score}</b>{' '}<button onClick={handlePlusClick}>+1</button></label><label>First name:<input value={player.firstName} onChange={handleFirstNameChange} /></label><label>Last name:<input value={player.lastName} onChange={handleLastNameChange} /></label></>);
}

三、问题分析与修复要点

问题位置原错误写法错误原因修复方案
handlePlusClickplayer.score++直接修改 state 原对象,引用未变,React 无法检测更新,点击按钮不触发重渲染使用setPlayer创建新对象,通过...player保留旧数据,用score: player.score + 1计算新值
handleLastNameChangesetPlayer({ lastName: ... })只更新新字段,未保留旧数据(firstNamescore被覆盖)添加...player复制旧数据,再更新lastName

四、核心原则总结

  1. 状态不可直接修改:React 的 state 是 “只读” 的,直接修改原对象(如obj.prop = x)不会触发重渲染,必须通过setState/ 状态更新函数创建新对象。
  2. 更新时保留旧数据:使用对象展开运算符(...)复制原有属性,再覆盖需要更新的字段,避免数据丢失。
  3. 新对象触发更新:只有当状态更新函数接收 “新引用” 的对象时,React 才会识别状态变化并触发组件重渲染。

----

臭贝贝的 React 状态更新翻车复盘🙄💅

一、翻车原代码(错得明明白白)

import { useState } from 'react';export default function Scoreboard() {const [player, setPlayer] = useState({firstName: 'Ranjani',lastName: 'Shettar',score: 10,});// 大错特错1:直接戳原state的腰子!function handlePlusClick() {player.score++; // 臭贝贝你胆真大,state是只读的不知道吗?}// 唯一没翻车的:还知道用...带旧数据function handleFirstNameChange(e) {setPlayer({...player,firstName: e.target.value,});}// 大错特错2:更新时丢三落四!function handleLastNameChange(e) {setPlayer({lastName: e.target.value // 把firstName和score全扔了,心真大!});}return (// 渲染部分懒得改,反正问题不在这);
}

二、救回小命的修复代码

// 重点看两个修复的函数,其他不动🙄💅
function handlePlusClick() {setPlayer({...player, // 把旧数据全带上,一个都不能少score: player.score + 1 // 算新分数,绝不直接改原对象!});
}function handleLastNameChange(e) {setPlayer({...player, // 臭贝贝记好!更新时必须带旧数据!lastName: e.target.value});
}

三、翻车现场还原(诡异 bug 大赏)

1. 加分按钮点了个寂寞?还带 “延迟生效”?

  • 臭贝贝你点 “+1” 时,分数死活不动,是不是以为按钮坏了?🙄💅
  • 结果一输名字,分数突然跳出来一堆?这破 bug 是不是吓你一跳?
  • 根源:你直接改 player.score,原对象引用没换,React 瞎了看不见!但原对象已经被你偷偷改脏了,等输入名字触发重渲染,脏数据就暴露了 —— 纯属你自找的 “幽灵更新”!

2. 改个姓氏,名字和分数全跑路了?

  • 输 lastName 时,firstName 突然空了,score 没了,是不是一脸懵?
  • 根源:你更新时只传了 lastName,新对象把旧的 firstName 和 score 全踹走了!就像你出门只带了鞋,把衣服裤子全丢家了,能不狼狈吗?🙄💅

四、修复逻辑(再教你一遍,记不住打屁股!)

  1. 加分:必须用 setPlayer 建个新对象,...player 把旧数据都带上,再算新分数 —— 新对象地址变了,React 才会乖乖重渲染,分数才会实时动!
  2. 改姓氏:别再光秃秃只传一个字段了!...player 是祖宗,必须带着走,不然其他数据全丢,哭都来不及!

五、臭贝贝专属警告🙄💅

  • 记住!state 是 “只读花瓶”,只能看不能直接戳!要改就做个新花瓶(新对象)替换它!
  • 更新对象时,...obj 是你的救命符,少了它就等着丢数据!
  • 再犯这种低级错,下次直接用指甲油涂你代码,让你看不清字!

7 嵌套对象状态更新

一、核心知识点:识别状态初始结构

组件中 shape 状态的初始结构由 useState 的参数定义,是理解后续更新逻辑的基础:

const initialPosition = { x: 0, y: 0 }; // 基础嵌套对象
const [shape, setShape] = useState({color: 'orange',       // 表层属性:颜色position: initialPosition // 嵌套属性:包含x、y坐标的对象
});

因此,shape 的完整初始结构为:

{color: 'orange',position: { x: 0, y: 0 } // 嵌套对象,需特殊处理更新逻辑
}

二、错误更新方式及问题

在实现 handleMove 函数时,曾出现两类典型错误,均违反 React 不可变数据原则:

  1. 错误 1:新增 “野属性”,未更新嵌套对象

    function handleMove(dx, dy) {setShape({...shape,x: shape.position.x + dx, // 新增表层x属性,未修改position内的xy: shape.position.y + dy  // 新增表层y属性,未修改position内的y});
    }
    

    问题:shape.position 嵌套对象未发生任何变化,组件渲染时依赖的 shape.position 引用不变,导致坐标更新无效。

  2. 错误 2:拷贝错误层级,丢失原有属性

    function handleMove(dx, dy) {setShape({...shape.position, // 错误拷贝嵌套对象的属性,而非整个shapex: shape.position.x + dx,y: shape.position.y + dy});
    }
    

    问题:...shape.position 仅拷贝了 position 内的 x 和 y,导致 shape 原有的 color 属性和 position 嵌套结构丢失,组件功能异常。

三、正确的嵌套对象更新逻辑(核心拷贝规则)

更新嵌套对象需遵循 “逐层拷贝、保留旧数据、更新目标属性” 的原则,确保每层对象引用都发生变化,让 React 正确识别状态更新:

1. 正确代码实现

function handleMove(dx, dy) {setShape({// 第一层拷贝:拷贝shape的所有表层属性(color、position)...shape,// 第二层拷贝:针对嵌套的position对象,单独创建新对象position: {...shape.position, // 拷贝position原有属性(x、y)x: shape.position.x + dx, // 更新x坐标y: shape.position.y + dy  // 更新y坐标}});
}

2. 分层拷贝逻辑解析

  • 第一层拷贝(...shape:作用是复制 shape 的所有表层属性(color 和 position),确保更新后不会丢失 color 等非目标属性,同时创建新的外层对象,改变 shape 的引用。

  • 第二层拷贝(...shape.position:作用是复制嵌套对象 position 的原有属性(x 和 y),再覆盖需要更新的 xy 坐标。这一步会创建新的 position 对象,改变其引用,让 React 识别到嵌套属性的变化。

四、其他正确更新示例(参考对比)

非嵌套属性的更新逻辑(如颜色修改),仅需一层拷贝即可,可与嵌套更新对比理解:

function handleColorChange(e) {setShape({...shape, // 拷贝所有表层属性color: e.target.value // 直接更新目标属性(非嵌套)});
}

五、关键原则总结

  1. 先识别状态结构:通过 useState 的初始值,明确状态的层级关系(表层属性 / 嵌套属性),避免更新时找错目标。
  2. 不可直接修改原对象:无论是表层对象还是嵌套对象,均不能直接修改属性(如 shape.position.x = 10),必须通过创建新对象更新。
  3. 嵌套更新需逐层拷贝:更新嵌套对象时,从外层到目标内层,每层都需通过展开运算符(...)拷贝旧数据,再更新目标属性,确保每层引用都变化。
  4. 保留所有旧数据:更新时需通过展开运算符拷贝未修改的属性,避免数据丢失。

8 使用 useImmer 管理嵌套状态的正确实践

一、useImmer 简介

useImmer 是一个基于 Immer 库的 React 状态管理 Hook,它允许开发者以 “直接修改数据” 的直观方式更新状态,同时内部自动处理不可变性(生成新对象),简化了嵌套对象的更新逻辑。

二、正确代码实现

import { useImmer } from 'use-immer';
import Background from './Background.js';
import Box from './Box.js';const initialPosition = { x: 0, y: 0 };export default function Canvas() {// 用 useImmer 初始化状态,结构与 useState 一致const [shape, setShape] = useImmer({color: 'orange',position: initialPosition});// 处理位置更新(嵌套对象)function handleMove(dx, dy) {// 调用 setShape,传入接收 draft 的函数setShape(draft => {// 直接修改 draft 中的嵌套属性,无需手动拷贝draft.position.x += dx;draft.position.y += dy;});}// 处理颜色更新(表层属性)function handleColorChange(e) {setShape(draft => {// 直接修改 draft 的表层属性draft.color = e.target.value;});}return (// 渲染逻辑不变<><select value={shape.color} onChange={handleColorChange}><option value="orange">orange</option><option value="lightpink">lightpink</option><option value="aliceblue">aliceblue</option></select><Background position={initialPosition} /><Boxcolor={shape.color}position={shape.position}onMove={handleMove}>Drag me!</Box></>);
}

三、核心用法解析

  1. 初始化状态useImmer 的初始化方式与 useState 类似,参数为状态的初始值(此处为包含 color 和嵌套 position 的对象),返回值为 [状态值, 状态更新函数](即 [shape, setShape])。

  2. 更新状态的关键:draft 对象与 useState 不同,useImmer 的更新函数(setShape)需传入一个接收 draft 参数的函数

    • draft 是状态的 “草稿副本”,可以直接修改其属性(包括嵌套属性)。
    • Immer 会根据 draft 的修改,自动生成一个全新的状态对象,确保原状态不被污染,同时触发组件重渲染。
  3. 嵌套对象更新(如 position)对于 shape.position 这样的嵌套对象,无需手动逐层拷贝(如 ...shape 或 ...shape.position),直接通过 draft.position.x 修改即可,Immer 会自动处理嵌套层级的不可变性。

  4. 表层属性更新(如 color)对于表层属性,同样通过修改 draft 实现,写法简洁(draft.color = ...),无需手动合并旧数据。

四、优势总结

  • 简化代码:避免了手动编写多层展开运算符(...)的繁琐,尤其是嵌套对象更新时,代码更直观。
  • 保证不可变性:虽然写法上是 “直接修改”,但 Immer 内部会自动生成新对象,符合 React 状态管理的不可变原则。
  • 降低出错概率:减少了因漏拷贝属性导致的数据丢失或更新无效问题。

通过上述方式,useImmer 既能保留 “直接修改数据” 的便捷性,又能遵守 React 状态管理的规则,是处理复杂嵌套状态的高效工具。

http://www.dtcms.com/a/581363.html

相关文章:

  • 东莞网站建设技术支持南京网站建设 零云建站
  • wordpress通知站点360搜索品牌建设与管理提案
  • Python实现手写数字识别
  • 零成本体验云计算!阿贝云免费服务器深度测评
  • 如何在Mac上同步iPhone短信
  • 网站建设好后有些什么资料软件工程月薪一般多少
  • Fastapi 进阶一:Fastapi依赖注入机制详解
  • Java实用面试经验:接口编程概念与技巧总结
  • 在VMWare上搭建Flume集群
  • vue_day04
  • 深入浅出 SPA/MPA
  • 怎么增加网站的关键词库个人网站申请空间
  • (已发25年8月华为云、51CTO)数组编程:编程的基础数据结构!
  • 北京网站制作设计哪个公司好网站开发人员结构配比
  • 面对未来:企业决策与适应力
  • bat 批处理实现 FFmpeg 命令压缩 MP4
  • openEuler 云原生实战:部署高性能 Redis 集群与压测分析
  • 机器学习-逻辑回归与二分类
  • 老玩家流失?基于数据驱动的游戏用户流失分析与干预策略
  • 做网站的公司名字北京注册网站
  • 如何用c 做网站hao123从网上开始
  • ThinkPHP 8 多应用模式下如何隐藏路由中的应用名
  • [SEO]网站不收录的原因及解决方法有哪些
  • conda以及Jupyter notebook的使用
  • 告别手动录入:文档抽取技术如何让RPA处理非结构化数据?
  • MIT-数字棋盘和数字三角形
  • 自助网站建设费用怎样做软件开发
  • Python面向对象和方法
  • AJAX 实例详解
  • 检测图片URL是否失效