欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React?Hook?四種組件優(yōu)化總結

 更新時間:2022年07月27日 10:21:15   作者:??河畔一角?  
這篇文章主要介紹了React?Hook四種組件優(yōu)化總結,文章圍繞主題展開詳細的內容介紹,具有一定的參考價孩子,需要的朋友可以參考一下

前言

React Hook 已成為當前最流行的開發(fā)范式,React 16.8 以后基于 Hook 開發(fā)極大簡化開發(fā)者效率,同時不正確的使用 React Hook也帶來了很多的性能問題,本文梳理基于 React Hook 開發(fā)組件的過程中如何提高性能。

組件抽取

優(yōu)化前

每次點擊 Increase 都會引起子組件 Child 的渲染,哪怕子組件并沒有狀態(tài)變化

function?Before(){
????console.log('Demo1?Parent')
????let?[count,setCount]?=?useState(0)
????let?[name,setName]?=?useState('-')
????const?handleClick?=?()=>{
????????setCount(count+1)
????}
????const?handleInput?=?(e)=>{
????????setName(e.target.value)
????}
????return?(
????????<div>
????????????<div?className='l50'>
????????????????<label>計數(shù)器:</label>
????????????????<span?className='mr10'>{count}</span>
????????????????<button?className='ml10'?onClick={handleClick}>Increase</button>
????????????</div>
????????????<div?className='l50'>
????????????????<label?htmlFor="">改變子組件:</label>
????????????????<input?type="text"?onChange={handleInput}/>
????????????</div>
????????????<hr?/>
????????????<Child?name={name}/>
????????</div>
????)
}
//?子組件
function?Child(props){
????console.log('Demo1?Child')
????return?(
????????<div?className='l50'>
????????????子組件渲染:{props.name}
????????</div>
????)
}

優(yōu)化后

只需要把 Increase 抽取成獨立的組件即可。此時點擊按鈕,子組件并不會渲染。

/**
?*?優(yōu)化后,Increase提取以后,上下文發(fā)生變化,組件內
?*?@returns?
?*/
function?Increase(){
????console.log('Child?Increase')
????let?[count,setCount]?=?useState(0)
????const?handleClick?=?()=>{
????????setCount(count+1)
????}
????return?(
????????<div>
????????????<div?className='l50'>
????????????????<label>計數(shù)器:</label>
????????????????<span?className='mr10'>{count}</span>
????????????????<button?className='ml10'?onClick={handleClick}>Increase</button>
????????????</div>
????????</div>
????)
}
function?After(){
????console.log('Demo1?Parent')
????let?[name,setName]?=?useState('-')
????const?handleInput?=?(e)=>{
????????setName(e.target.value)
????}
????return?(
????????<div>
????????????<Increase/>
????????????<div?className='l50'>
????????????????<label?htmlFor="">改變子組件:</label>
????????????????<input?type="text"?onChange={handleInput}/>
????????????</div>
????????????<Child?name={name}/>
????????</div>
????)
}
//?子組件
function?Child(props){
????console.log('Demo1?Child')
????return?(
????????<div?className='l50'>
????????????子組件渲染:{props.name}
????????</div>
????)
}

memo 優(yōu)化組件

同樣基于上述優(yōu)化前代碼,如果不抽取組件,使用 memo 優(yōu)化后,當點擊按鈕后,也不會觸發(fā)二次渲染。

//?優(yōu)化前
function?AfterMemo(){
????console.log('Demo1?Parent')
????let?[count,setCount]?=?useState(0)
????let?[name,setName]?=?useState('-')
????const?handleClick?=?()=>{
????????setCount(count+1)
????}
????const?handleInput?=?(e)=>{
????????setName(e.target.value)
????}
????return?(
????????<div>
????????????<div?className='l50'>
????????????????<label>計數(shù)器:</label>
????????????????<span?className='mr10'>{count}</span>
????????????????<button?className='ml10'?onClick={handleClick}>Increase</button>
????????????</div>
????????????<div?className='l50'>
????????????????<label?htmlFor="">改變子組件:</label>
????????????????<input?type="text"?onChange={handleInput}/>
????????????</div>
????????????<Child?name={name}/>
????????</div>
????)
}

//?子組件
const?Child?=?memo((props)=>{
????console.log('Demo1?Child')
????return?(
????????<div?className='l50'>
????????????子組件渲染:{props.name}
????????</div>
????)
})

React.memo 語法

React.memo 為高階組件,與 React.PureComponent相似。

function?TestComponent(props){
??//?使用?props?渲染
}
function?areEqual(prevProps,nextProps){
??/*
??如果把?nextProps?傳入?render?方法的返回結果與
??將?prevProps?傳入?render?方法的返回結果一致則返回?true,
??否則返回?false
??*/
}
export?default?React.memo(TestComponent,areEqual)

與 class 組件中 shouldComponentUpdate() 方法不同的是,如果 props 相等,areEqual 會返回 true;如果 props 不相等,則返回 false。這與 shouldComponentUpdate 方法的返回值相反。

useCallback 優(yōu)化組件

如果已經(jīng)用了 memo ,當遇到下面這種場景時,同樣會觸發(fā)子組件渲染。比如,給 Child 綁定一個 handleClick ,子組件內部增加一個按鈕,當點擊子組件的按鈕時,更改 count 值,即使沒有發(fā)生 name 變化,也同樣會觸發(fā)子組件渲染,為什么?memo 不是會判斷 name 變化了,才會更新嗎?

function?Before(){
????console.log('Demo1?Parent')
????let?[count,setCount]?=?useState(0)
????let?[name,setName]?=?useState('-')
????const?handleClick?=?()=>{
????????setCount(count+1)
????}
????const?handleInput?=?(e)=>{
????????setName(e.target.value)
????}
????const?handleChange?=?()=>{
????????setCount(count+1)
????}
????return?(
????????<div>
????????????<div?className='l50'>
????????????????<label>計數(shù)器:</label>
????????????????<span?className='mr10'>{count}</span>
????????????????<button?className='ml10'?onClick={handleClick}>Increase</button>
????????????</div>
????????????<div?className='l50'>
????????????????<label?htmlFor="">改變子組件:</label>
????????????????<input?type="text"?onChange={handleInput}/>
????????????</div>
????????????<Child?name={name}?handleClick={handleChange}/>
????????</div>
????)
}

//?子組件
const?Child?=?memo((props)=>{
????console.log('Demo1?Child')
????return?(
????????<div?className='l50'>
????????????子組件渲染:{props.name}
????????????<button?onClick={props.handleClick}>更改count</button>
????????</div>
????)
})

并不是 memo 沒有生效,是因為當狀態(tài)發(fā)生變化時,父組件會從新執(zhí)行,導致從新創(chuàng)建了新的handleChange 函數(shù),而 handleChange 的變化導致了子組件的再次渲染。

優(yōu)化后

點擊父組件的Increase按鈕,更改了 count 值,經(jīng)過 useCallback 包裹 handleChange 函數(shù)以后,我們會發(fā)現(xiàn)子組件不再渲染,說明每當父組件執(zhí)行的時候,并沒有創(chuàng)建新的 handleChange 函數(shù),這就是通過 useCallback 優(yōu)化后的效果。 即使我們點擊子組件的按鈕,也同樣不會觸發(fā)子組件的渲染,同樣 count 會進行累加。

function?After(){
????console.log('Demo1?Parent')
????let?[count,setCount]?=?useState(0)
????let?text?=?useRef();
????let?[name,setName]?=?useState('-')
????const?handleClick?=?()=>{
????????setCount(count+1)
????}
????const?handleInput?=?(e)=>{
????????setName(e.target.value)
????}
????const?handleChange?=?useCallback(()=>{
????????//?為了讓?count?能夠累加,我們使用ref?獲取值
????????let?val?=?parseInt(text.current.textContent);
????????setCount(val+1)
????},[])
????return?(
????????<div>
????????????<div?className='l50'>
????????????????<label>計數(shù)器:</label>
????????????????<span?className='mr10'?ref={text}>{count}</span>
????????????????<button?className='ml10'?onClick={handleClick}>Increase</button>
????????????</div>
????????????<div?className='l50'>
????????????????<label?htmlFor="">改變子組件:</label>
????????????????<input?type="text"?value={name}?onChange={handleInput}/>
????????????</div>
????????????<Child?name={name}?handleClick={handleChange}/>
????????</div>
????)
}

useCallback 作用

//?用法
useCallback(()=>{
??//?to-do
},[])

//?示例
function?App(){
??//?點擊按鈕調用此函數(shù),但返回被緩存
??const?onClick?=?useCallback(()?=>?{
????console.log('我被緩存了,怎么點擊都返回一樣');
??},?[]);

??return?(?
????<button?onClick={onClick}>點擊</button>
??);
}
  • useCallback 接收 2 個參數(shù),第一個為緩存的函數(shù),第二個為依賴值
  • 主要用于緩存函數(shù),第二次會返回同樣的結果。

useMemo 優(yōu)化

我們定義了一個total函數(shù),內部使用 1 填充了100次,通過 reduce 計算總和,經(jīng)過測試發(fā)現(xiàn)點擊 Increase按鈕后,只會執(zhí)行 total1 ,不會執(zhí)行 total2,假設total計算量巨大,就會造成內存的浪費,通過 useMemo 可以幫我們緩存計算值。

function?Before(){
????console.log('Demo1?Parent')
????let?[count,setCount]?=?useState(0)
????const?handleClick?=?()=>{
????????setCount(count+1)
????}
????const?total1?=?()=>{
????????console.log('計算求和1')
????????let?arr?=?Array.from({?length:100?}).fill(1)
????????return?arr.reduce((prev,next)=>prev+next,0)
????}
????//?緩存對象值
????const?total2?=?useMemo(()=>{
????????console.log('計算求和2')
????????let?arr?=?Array.from({?length:100?}).fill(1)
????????return?arr.reduce((prev,next)=>prev+next,0)
????},[count])
????return?(
????????<div>
????????????<div?className='l50'>
????????????????<label>計數(shù)器:</label>
????????????????<span?className='mr10'>{count}</span>
????????????????<button?className='ml10'?onClick={handleClick}>Increase</button>
????????????</div>
????????????<div>
????????????????<label>總和:</label>
????????????????<span>{total1()}</span>
????????????????<span>{total2}</span>
????????????</div>
????????</div>
????)
}

useMemo 語法

const?memoizedValue?=?useMemo(()?=>?computeExpensiveValue(a,?b),?[a,?b]);
  • 傳入一個函數(shù)進去,會返回一個 memoized 值,需要注意的是,函數(shù)內必須有返回值
  • 第二個參數(shù)會依賴值,當依賴值更新時,會從新計算。

useCallback 和 useMemo 區(qū)別

他們都用于緩存,useCallback 主要用于緩存函數(shù),返回一個 緩存后 函數(shù),而 useMemo 主要用于緩存值,返回一個緩存后的值。

到此這篇關于React Hook 四種組件優(yōu)化總結的文章就介紹到這了,更多相關React Hook 組件優(yōu)化內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • React實現(xiàn)pc端的彈出框效果

    React實現(xiàn)pc端的彈出框效果

    這篇文章主要為大家詳細介紹了React實現(xiàn)pc端的彈出框效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • React數(shù)據(jù)傳遞之組件內部通信的方法

    React數(shù)據(jù)傳遞之組件內部通信的方法

    這篇文章主要介紹了React數(shù)據(jù)傳遞之組件內部通信的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • 解決React報錯`value` prop on `input` should not be null

    解決React報錯`value` prop on `input` should&

    這篇文章主要為大家介紹了React報錯`value` prop on `input` should not be null解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • react項目使用redux初始化方式

    react項目使用redux初始化方式

    這篇文章主要介紹了react項目使用redux初始化方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 一看就懂的ReactJs基礎入門教程-精華版

    一看就懂的ReactJs基礎入門教程-精華版

    現(xiàn)在最熱門的前端框架有AngularJS、React、Bootstrap等。自從接觸了ReactJS,ReactJs的虛擬DOM(Virtual DOM)和組件化的開發(fā)深深的吸引了我,下面來跟我一起領略ReactJs的風采吧~~ 文章有點長,耐心讀完,你會有很大收獲哦
    2021-04-04
  • React虛擬列表的實現(xiàn)代碼

    React虛擬列表的實現(xiàn)代碼

    最近看了vueuse的useVirtualList的實現(xiàn)方式,發(fā)現(xiàn)虛擬滾動效果不錯,就嘗試著同樣的寫法改成react版本,虛擬列表主要包含三部分組成,offset,viewcapacity,overscan,本文就給大家介紹一下React虛擬列表的實現(xiàn),需要的朋友可以參考下
    2023-08-08
  • 詳解React組件卸載怎么中止遞歸方法

    詳解React組件卸載怎么中止遞歸方法

    最近在處理項目代碼的時候,出現(xiàn)了一個bug,組件中的方法在組件卸載后仍然在執(zhí)行,代碼片段發(fā)給我看,但是變量的用意我也不懂,只看到有方法調用自身方法,這不就是遞歸嘛,所以本文詳細給大家介紹了React組件卸載怎么中止遞歸方法,需要的朋友可以參考下
    2024-01-01
  • React的createElement和render手寫實現(xiàn)示例

    React的createElement和render手寫實現(xiàn)示例

    這篇文章主要為大家介紹了React的createElement和render手寫實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 詳解React中的this指向

    詳解React中的this指向

    這篇文章主要介紹了React中的this指向的相關資料,幫助大家更好的理解和學習使用React,感興趣的朋友可以了解下
    2021-04-04
  • react實現(xiàn)換膚功能的示例代碼

    react實現(xiàn)換膚功能的示例代碼

    這篇文章主要介紹了react實現(xiàn)換膚功能的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08

最新評論