詳解React中的不可變值
什么是不可變值
函數(shù)式編程是指程序里面的函數(shù)和表達式都能像數(shù)學(xué)中的函數(shù)一樣,給定了輸入值,輸出是確定的。比如
let a = 1; let b = a + 1; => a = 1 b = 2;
變量b出現(xiàn),雖然使用了變量a的值,但是沒有修改a的值。
再看我們熟悉的react中的代碼,假如初始化了this.state = { count: 1 }
componentDidMount() { const newState = { ...state, count: 2 }; // { count: 2 } this.setState(newState); }
雖然我們使用了this.state,但是沒有修改this.state的引用地址和直接修改count的值,對待this.props也一樣。
為什么使用不可變值
React官網(wǎng)中給出三點好處:
- 簡化復(fù)雜的功能
不可變性使得復(fù)雜的特性更容易實現(xiàn)。
- 跟蹤數(shù)據(jù)的改變
如果直接修改數(shù)據(jù),那么就很難跟蹤到數(shù)據(jù)的改變。跟蹤數(shù)據(jù)的改變需要可變對象可以與改變之前的版本進行對比,這樣整個對象樹都需要被遍歷一次。
跟蹤不可變數(shù)據(jù)的變化相對來說就容易多了。如果發(fā)現(xiàn)對象變成了一個新對象,那么我們就可以說對象發(fā)生改變了。
- 確定在 React 中何時重新渲染
不可變性最主要的優(yōu)勢在于它可以幫助我們在 React 中創(chuàng)建 pure components。我們可以很輕松的確定不可變數(shù)據(jù)是否發(fā)生了改變,從而確定何時對組件進行重新渲染。
React性能優(yōu)化離不開不可變值
- 首先,我們都知道,shouldComponentUpdate鉤子函數(shù)默認返回true,即只要父組件更新,子組件一定更新。
- shouldComponentUdpate中可以接收兩個參數(shù),nextProps和nextState,假如我們通過判斷this.props.xxx和nextProps.xxx相等以及this.state.xxx與nextState.xxx相等,可以將返回值設(shè)置為false,說明此次并不需要更新子組件。
class CounterButton extends React.Component { constructor(props) { super(props); this.state = {count: 1}; } shouldComponentUpdate(nextProps, nextState) { if (this.props.color !== nextProps.color) { return true; } if (this.state.count !== nextState.count) { return true; } return false; } render() { return ( <button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button> ); } }
- React v15.3新增加了一個PureComponent類,能夠?qū)rops和state進行淺比較來減少render函數(shù)的執(zhí)行次數(shù),避免不必要的組件渲染,實現(xiàn)性能上的優(yōu)化。
- PureComponent是什么原理呢
我們知道JS中的變量類型分為基本類型(number、string、boolean、undefined、null、symbol)和引用類型(function、object、function),基本類型的值保存在棧內(nèi)存當中,引用類型的值保存在堆內(nèi)存當中,棧內(nèi)存中只保存指向堆內(nèi)存的引用。而淺比較就是只對棧內(nèi)存中的數(shù)據(jù)進行比較。
class App extends PureComponent { state = { items: [1, 2, 3] } handleClick = () => { const { items } = this.state; items.pop(); this.setState({ items }); } render() { return ( <div> <ul> {this.state.items.map(i => <li key={i}>{i}</li>)} </ul> <button onClick={this.handleClick}>delete</button> </div> ) } }
上邊這個例子使用了PureComponent,而且只改變了數(shù)組items里的值,而沒改變items的引用地址,所以認為items沒有發(fā)生變化,不會觸發(fā)render函數(shù),不會觸發(fā)組件的渲染。
如果想實現(xiàn)組件更新,可以按如下的方式,創(chuàng)建一個新的數(shù)組,將新數(shù)組的地址賦給items。
handleClick = () => { const { items } = this.state; items.pop(); var newItem = [...items]; this.setState({ item: newItem }); }
- PureComponent幫我們做了淺層的比較,所以要注意state時盡量合理,如果需要出現(xiàn)引用嵌套引用的數(shù)據(jù)結(jié)構(gòu)的話,可以配合Immutable.js。
- 什么是Immutable
(1) Immutable是一旦創(chuàng)建,就不能被更改的數(shù)據(jù)。(2) 對Immutable對象的任何修改或添加刪除操作都會返回一個新的Immutable對象。(3)Immutable實現(xiàn)的原理是Persistent Data Structure(持久化數(shù)據(jù)結(jié)構(gòu)),也就是是永久數(shù)據(jù)創(chuàng)建新數(shù)據(jù)時,要保證舊數(shù)據(jù)同時可用且不變。(4)同時為了避免deepCopy把所有節(jié)點都復(fù)制一遍帶來的性能損耗,Immutable使用了Structural Sharing(結(jié)構(gòu)共享),即如果對象樹結(jié)點發(fā)生變化,只修改這個結(jié)點和受它影響的父節(jié)點,其他結(jié)點進行共享。
最后,如果想要在組件層面進行淺比較,可以使用React.memo()函數(shù)
總結(jié)
其實還是官網(wǎng)說的不可變性的第三條優(yōu)勢,也是最主要的優(yōu)勢,就是不可變性可以幫助我們在React中使用PureComponent。我們可以很輕松的確定數(shù)據(jù)是否發(fā)生了改變,組件何時需要發(fā)生重新渲染。
如果我們改變了state的值,shouldComponentUpdate獲取到當前state和nextState,或者props和nextProps比較出來的值都是完全一樣的,都會返回false,即使我們做了setState的操作,UI也不會發(fā)生更新。
PureComponent最好是搭配Immutable.js進行使用,來達到性能優(yōu)化的目的。
結(jié)合React.memo來避免沒必要的組件的更新渲染。
以上就是詳解React中的不可變值的詳細內(nèi)容,更多關(guān)于React中的不可變值的資料請關(guān)注腳本之家其它相關(guān)文章!
- react獲取input輸入框的值的方法示例
- react ant Design手動設(shè)置表單的值操作
- react使用antd表單賦值,用于修改彈框的操作
- 在react項目中使用antd的form組件,動態(tài)設(shè)置input框的值
- react PropTypes校驗傳遞的值操作示例
- React傳值 組件傳值 之間的關(guān)系詳解
- react 組件傳值的三種方法
- Vue和React組件之間的傳值方式詳解
- React父子組件間的傳值的方法
- React key值的作用和使用詳解
- react 父組件與子組件之間的值傳遞的方法
- React 子組件向父組件傳值的方法
- react-router實現(xiàn)跳轉(zhuǎn)傳值的方法示例
相關(guān)文章
Hello?React的組件化方式之React入門小案例演示
這篇文章主要介紹了Hello?React的組件化方式-React入門小案例,本文通過Hello?React的案例,?來體驗一下React開發(fā)模式,?以及jsx的語法,需要的朋友可以參考下2022-10-10詳解React Native 采用Fetch方式發(fā)送跨域POST請求
這篇文章主要介紹了詳解React Native 采用Fetch方式發(fā)送跨域POST請求,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11React useMemo和useCallback的使用場景
這篇文章主要介紹了React useMemo和useCallback的使用場景,幫助大家更好的理解和學(xué)習使用React框架,感興趣的朋友可以了解下2021-04-04React Native全面屏狀態(tài)欄和底部導(dǎo)航欄適配教程詳細講解
最近在寫 React Native 項目,調(diào)試應(yīng)用時發(fā)現(xiàn)頂部狀態(tài)欄和底部全面屏手勢指示條區(qū)域不是透明的,看起來很難受。研究了一下這個問題,現(xiàn)在總結(jié)一下解決方案,這篇文章主要介紹了React Native全面屏狀態(tài)欄和底部導(dǎo)航欄適配教程2023-01-01Zustand介紹與使用 React狀態(tài)管理工具的解決方案
本文主要介紹了Zustand,一種基于React的狀態(tài)管理庫,Zustand以簡潔易用、靈活性高及最小化原則等特點脫穎而出,旨在提供簡單而強大的狀態(tài)管理功能2024-10-10