您好,登錄后才能下訂單哦!
今天小編給大家分享一下react中的useMemo怎么使用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
react
中是通過一次次的 re-render
(重新渲染)保持我們的值及時的更新到頁面上的,每次重新渲染都是一次快照,可以把它想象成一張張的照片,在某個時刻它應該是什么樣子的
把創建函數和依賴數組項作為參數傳入 useMemo
,它僅僅會在數組依賴項中的值改變時才會重新計算值
這種優化有助于避免在每次渲染時都進行高開銷的計算
useMemo 的函數在渲染期間執行,所以不該在此期間做的操作請去除
如果沒有提供依賴數據,每次都會重新計算值,相當于沒有優化了
以下代碼實現功能:找出 0
到 count
之間所有的偶數,count
可以動態改變,實時渲染在頁面上,count
改變則會引起 re-render
import React, { useState } from 'react'; export default () => { const [count, setCount] = useState(100); const arr = []; for (let i = 0; i < count; i++) { if (i % 2 === 0) { arr.push(i); } } return ( <> <form> <label htmlFor="num">Your number:</label> <input type="number" value={count} onChange={(event) => { // 設置最大值為 100000 let num = Math.min(100_000, Number(event.target.value)); setCount(num); }} /> </form> <p> 有{arr.length}偶數在 0 到 {count} 之間:<span>{arr.join(', ')}</span> </p> </> ); };
下面代碼增加了計時器,在頁面顯示實時的時間,這樣頁面每秒鐘都會 re-render
,也會每秒鐘重新篩選一次偶數(盡管 count
并沒有變化)
import React, { useState, useEffect } from 'react'; export default () => { const [count, setCount] = useState(100); const [curTime, setCurTime] = useState(''); const useTime = () => { useEffect(() => { const intervalId = window.setInterval(() => { let time = new Date(); setCurTime(time.toLocaleString()); }, 1000); return () => { window.clearInterval(intervalId); }; }, []); return curTime; }; const time = useTime(); const arr = []; for (let i = 0; i < count; i++) { if (i % 2 === 0) { arr.push(i); } } return ( <> <form> <div>{time}</div> <label htmlFor="num">Your number:</label> <input type="number" value={count} onChange={(event) => { // 設置最大值為 100000 let num = Math.min(100_000, Number(event.target.value)); setCount(num); }} /> </form> <p> 有{arr.length}偶數在 0 到 {count} 之間:<span>{arr.join(', ')}</span> </p> </> ); };
那我們需要的是啥,雖然每秒鐘都在重新獲取時間,但是我們的 count
如果并沒有變化的話,我們沒必要去一直重新計算它的,特別如果 count
的值特別大的時候,特別如果在一些舊設備上看著就會顯得卡頓,極其影響性能 有了 useMemo 就是 so easy 啊
我們來改造下計算偶數地方的代碼:這樣如果 count
不變的情況下,不會進行重復的計算,直接使用上次的值
const arr = useMemo(() => { const temp = []; for (let i = 0; i < count; i++) { if (i % 2 === 0) { temp.push(i); } } return temp; }, [count]);
既然講到 useMemo 了,那么 useCallback、React.memo 也順便說下吧,一個效果的東西,只不過將返回的值從對象變成了函數或者組件
React.memo:當其作用于函數式組件并且作為子組件時, 每次父組件更新后, 會淺對比傳來的 props 是否變化, 若沒變化, 則子組件不更新
useCallback:作用和 useMemo 一致,返回一個函數
下面看個小栗子:
// 父組件代碼:一個計時器每秒更新時間,父組件每秒不停的 re-render,改變 count 值的 onCountChange 函數傳入子組件 import React, { useState, useEffect, useCallback } from 'react'; import Child from './child'; export default () => { const [count, setCount] = useState(100); const [curTime, setCurTime] = useState(''); const useTime = () => { useEffect(() => { const intervalId = window.setInterval(() => { let time = new Date(); setCurTime(time.toLocaleString()); }, 1000); return () => { window.clearInterval(intervalId); }; }, []); return curTime; }; const time = useTime(); const onCountChange = () => { setCount((count) => count + 100); }; console.log('re-render-father'); return ( <> <div>{time}</div> <div>{count}</div> <Child onCountChange={onCountChange} /> </> ); }; // 子組件代碼,接收 onCountChange 函數,并且用 React.memo 包裹函數 import React from 'react'; export default React.memo((props: any) => { const { onCountChange } = props; console.log('re-render-child'); return ( <> <div onClick={() => { onCountChange(); }} > 加100 </div> </> ); });
分析一下上面的栗子:
現象:父組件和子組件都會不停的 re-render
我子組件加了 React.memo ,雖然父組件因為計時器在不停的 re-render,但是我每次傳入 onCountChange 的函數都是一樣的啊,不是說比較 props 沒變就不會 re-render 嗎???為啥也會不停的 re-render 呢
原因:父組件在不停的 re-render 每次都會重新創建函數,在 js 中雖然兩個函數一模一樣,但是不是一個引用的話就不相等,所以 React.memo 在進行淺比較的時候就認為 props 變化了,子組件也會 re-render,造成了無效優化
解決辦法:既然知道了原因所在,那我們如何解決呢,那就讓它是同一個函數不就好了,那就用到了 useCallback 進行優化
const onCountChange = useCallback(() => { setCount((count) => count + 100); }, []);
或者可以用 useMemo:返回變成函數即可
const onCountChange = useMemo(() => { return () => { setCount((count) => count + 100); }; }, []);
由此可見 useCallback 為 useMemo 的語法糖而已
將函數用 useCallback 包裹一樣就會使用緩存的值,不會重新創建函數,也就不會重復 re-render 組件了。
以上就是“react中的useMemo怎么使用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。