useMemo[性能优化]
作用
- 缓存计算的值
- 解决React.memo中当依赖的数组地址发生改变时所带来的重新渲染问题
性能优化的手段
参数
- 参数一:需要被执行的任务,被包裹在一个函数里
- 参数二:依赖列表
与React.memo的区别
React.memo主要用于缓存整个函数组件,使它具备PureComponent的效果。但是在某些情况下,React.memo缓存的组件还是会重新渲染,例如引用的情况下。
实例1:进行大计算量函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import React from 'react'; import format from 'date-fns/format'; function App(){ const [selectedNum, setSelectedNum] = React.useState(100); const time = useTime(); const allPrimes = []; for(let counter=2;counter<selectedNum;counter++) if(isPrime(counter)) allPrimes.push(counter); return ( <> <p className="clock"> {format(time, 'hh:mm:ss a')} </p> <form> <label htmlFor="num">Your number:</label> <input type="number" value={selectedNum} onChange={(event)=>{ let num=Math.min(100000, Number(event.target.value)); setSelectedNum(num); }}/> </form> <p> There are {allPrimes.length} prime between 1 and {selectedNum}: <span className="prime-list"> {allPrimes.join(', ')} </span> </p> </> ) } function useTime(){ const [time, setTime] = React.useState(new Date()); React.useEffect(()=>{ const intervalId = window.setInterval(()=>{ setTime(new Date()); }, 1000); return ()=>{ window.clearInterval(intervalId); } }, []); return time; } function isPrime(n){ const max = Math.ceil(Math.sqrt(n)); if(n===2) return true; for(let counter=2;counter<=max;counter++) if(n%counter===0) return false; return true; } export default App;
|
上述场景中存在如下问题,当界面中的时间发生改变时,就需要重新计算下面所有的质数,即使输入的数值不变。
使用useMemo进行改造:
1 2 3 4 5 6 7 8
| const allPrimes = React.useMemo(()=>{ const result = []; for(let i=2;i<selectedNum;i++) if(isPrime(i)) result.push(i); return result; }, [selectedNum]);
|
实例2:保存的引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import React from 'react'; import Boxes from './Boxes'; function App(){ const [name, setName] = React.useState(''); const [boxWidth, setBoxWidth] = React.useState(1); const boxes = [ {flex: boxWidth, background:'hsl(345deg 100% 505)'}, {flex:3,background:'hsl(260deg 100% 40%)'}, {flex:1,background:'hsl(50deg 100% 60%)'} ]; return( <> <Boxes boxes={boxes} /> <section> <label htmlFor={`${id}-name`}> Name: </label> <input id={`${id}-name`} type="text" value={name} onChange={(event) => { setName(event.target.value); }} /> <label htmlFor={`${id}-box-width`}> First box width: </label> <input id={`${id}-box-width`} type="range" min={1} max={5} step={0.01} value={boxWidth} onChange={(event) => { setBoxWidth(Number(event.target.value)); }} /> </section> </> ) }
|
useCallback
与useMemo的区别
基本相同,useCallback是useMemo的语法糖。useMemo的功能比useCallback更齐全,useCallback主要用于缓存函数的。
示例
1 2 3 4 5
| const handleMegaBoost = React.useMemo(()=>{ return function(){ setCount((currentValue)=>currentValue+1234); } },[])
|
useMemo和useCallback的原理
他们内部是使用纯函数实现的。因为对于给定输入需要得出给定的输出,在输出保持不变的情况下就无需重新渲染。
useContext
作用
父组件传值给后代组件
性能问题
父组件每次执行都会引发子组件的渲染