網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
正文
不變性對(duì)應(yīng)的英文單詞是 Immutability,它不是 React 中的概念,但它對(duì)寫(xiě)一個(gè)正確的 React 程序至關(guān)重要。不考慮生命周期函數(shù) shouldComponentUpdate 對(duì)組件重新渲染造成的影響,當(dāng)組件的 state 發(fā)生變化時(shí),組件將被重新渲染。
你可曾遇到過(guò)這樣一種情況——你自認(rèn)為改變了 state 的值,但是組件沒(méi)有重新渲染?本文將揭露其中的緣由并介紹怎么編寫(xiě)符合 Immutability 原則的代碼。
什么是 immutable
immutable 指不發(fā)生變化,這意味著創(chuàng)建新的值去替換原來(lái)的值,而非改變?cè)瓉?lái)的值,與 immutable 相反的概念是 mutable,下面用代碼演示 mutable 和 immutable。
let user = {name: 'Bela'} user.name = 'CI' // 改變user的name屬性 user.age = 12 // 給user新增age屬性 user = {name: 'Bela'} // 用新的值替換原來(lái)的值
上述代碼第 2 行和第 3 行都屬于改變?cè)瓉?lái)的值,只有第四行是新建一個(gè)對(duì)象,用新對(duì)象替換原來(lái)的對(duì)象。下面調(diào)用函數(shù)進(jìn)一步說(shuō)明 immutable 與 mutable。
function addAgeMutable(user: User) { user.age = 12 // 修改原來(lái)的 return user } function addAgeImmutable(user: User) { const other = Object.assign({}, user) // 創(chuàng)建新的 other.age = 12 return other } let user1Original = {name: 'Bella'} let user1New = addAgeMutable(user1Original) // 用 mutable 的方式 let user2Original = {name: 'Bella'} let user2New = addAgeImmutable(user2Original) // 用 immutable 的方式 console.log('user1Original 與 user1New 相同嗎?',user1Original === user1New) // true console.log('user2Original 與 user2New 相同嗎?',user2Original === user2New) // false
上述 addAgeMutable 函數(shù)直接在入?yún)⑸闲略?age 屬性,但 addAgeImmutable 函數(shù)沒(méi)有改變?nèi)雲(yún)ⅲ切陆艘粋€(gè)對(duì)象,在新對(duì)象上添加age屬性。
總結(jié)一下,immutable 是指不修改原來(lái)的;mutable 是指在原來(lái)的基礎(chǔ)上修改。通過(guò) mutable 的方式修改變量會(huì)導(dǎo)致修改前后變量的引用不變。某些操作數(shù)組的方法會(huì)讓原來(lái)的數(shù)組發(fā)生變化,比如:push/pop/shift/unshift/splice,這些方法是 mutable 的,而有一些操作數(shù)組的方法不會(huì)讓原來(lái)的數(shù)組發(fā)生變化,而是返回一個(gè)新組件,比如:slice/concat,這些函數(shù)是 immutable 的。字符串、布爾值和數(shù)值操作都不改變?cè)瓉?lái)的值,而是創(chuàng)建一個(gè)新的值。
React 與 Immutability
在 React 程序中,組件的 state 必須具備不變性,接下來(lái)演示修改state的正確與不正確的方式。為了說(shuō)明state的組成結(jié)構(gòu),先定義個(gè)State接口,代碼如下:
interface State { user: User hobbies: string[] time: string }
從上述接口可以看出,組件有三個(gè)狀態(tài),分別為:user、hobbies 和 time,它們的數(shù)據(jù)類型各不相同。
修改 state 的錯(cuò)誤案例
下面羅列的案例試圖用 mutable 的方式修改 state,這些做法全部是錯(cuò)誤的。
// 案例一 this.state.user.age = 13 // 案例二 this.setState({ user: Object.assign(this.state.user, {age: 13}) }) // 案例三 this.setState({ hobbies: this.state.hobbies.reverse(), }) // 案例四 this.state.hobbies.length = 0 this.setState({ hobbies: this.state.hobbies, })
- 案例一: 直接修改 user 的內(nèi)部結(jié)構(gòu),修改前后 user 的引用不變。
- 案例二: 錯(cuò)誤使用 Object.assign,Object.assign 將第二個(gè)參數(shù)的屬性合并到第一個(gè)參數(shù)上,然后將第一個(gè)參數(shù)返回,這意味著案例二還是修改了user的內(nèi)部結(jié)構(gòu),修改前后user的引用不變。
- 案例三: 使用reverse將數(shù)組翻轉(zhuǎn),它翻轉(zhuǎn)的是原數(shù)組,翻轉(zhuǎn)前后數(shù)據(jù)的引用不變。
- 案例四: 修改hobbies的長(zhǎng)度,修改前后hobbies的引用一樣。
上述四個(gè)案例都不符合數(shù)據(jù)一旦創(chuàng)建就不發(fā)生變化的原則,由于調(diào)用了 setState 方法,所以對(duì)于用 React.Component 創(chuàng)建的組件而言,不會(huì)發(fā)生故障,對(duì)于用 React.PureComponent 創(chuàng)建的組件,會(huì)引發(fā)故障,即:界面不更新。
修改 state 的正確案例
下面羅列的案例與錯(cuò)誤案例一一對(duì)應(yīng),它們通過(guò) immutable 的方式修改 state。
// 案例一 this.setState({ user: {...this.state.user, age: 13} }) // 案例二 this.setState({ user: Object.assign({},this.state.user, {age: 13}) }) // 案例三 this.setState({ hobbies: [...this.state.hobbies].reverse() }) // 案例四 this.setState({ hobbies: [] })
上述案例都是新建一個(gè)值,用新的值替換原來(lái)的值,符合數(shù)據(jù)一旦創(chuàng)建就不發(fā)生變化的原則。
總結(jié)
在 react 應(yīng)用中,更新 state 必須滿足 Immutability 原則,因?yàn)?React.memo、PureComponent shouldComponentUpdate 和 React Hooks 通過(guò)淺比較
確定 state 是否發(fā)生變更,如果變更 state 的方式不滿足 Immutability 原則,它們會(huì)認(rèn)為 state 的值沒(méi)有變化。
在更新 state 并重新渲染時(shí),React 會(huì)將類組件的 this.setState 與函數(shù)組件的 useState、useReducer hooks 區(qū)別對(duì)待。在函數(shù)組件中,React 要求所有 hooks 更新?tīng)顟B(tài)必須返回一個(gè)新的引用作為狀態(tài)值,如果 React 發(fā)現(xiàn)狀態(tài)更新來(lái)自 hook,它會(huì)檢查該值的引用是否與以前的引用相同,如果相同,它將退出該函數(shù)組件的渲染流程,最終用戶界面不更新。使用 this.setState 更新類的 state,React 并不關(guān)心狀態(tài)的引用是否變化,只要在類組件中調(diào)用 this.setState,該組件一定會(huì)重新渲染。
原文鏈接:https://juejin.cn/post/7165338973806526501
相關(guān)推薦
- 2022-04-28 C++中的友元函數(shù)與友元類詳情_(kāi)C 語(yǔ)言
- 2022-08-15 SynchronizedList和Vector的區(qū)別
- 2022-07-04 如何生成對(duì)角矩陣?numpy.diag_python
- 2022-05-10 remote: error: GE007: Your push would publish a pr
- 2023-04-07 React?styled?components樣式組件化使用流程_React
- 2023-07-29 el-tree 只展示選中值
- 2022-07-26 Python+Seaborn繪制分布圖的示例詳解_python
- 2022-07-18 Stack和Queue容器的系列操作( 詳解 )
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支