为了减少组件渲染,我们可以优化,设置组件的属性变了才重新渲染,如果没变则不渲染。
useMemo 减少对象创建的次数
useCallback 减少函数创建的次数
useCallback 的原理
function Child(props) {
console.log('Child');
return (
<button onClick={props.handle}>子:</button>
)
}
// memo:如果你想让一个函数组件有一个功能,如果属性不变,就不要刷新
let MemoChild = React.memo(Child);
let lastAdd;
function App() {
let [number, setNumber] = React.useState(0);
let [name, setName] = React.useState('zhufeng');
// 每次渲染App都要声明一个新的函数,进行优化,依赖变量发生改变的话才会重新执行得到函数,否则始终用上次的函数
let handle = React.useCallback(() => setNumber(number + 1), [number]);
console.log(lastAdd === handle);
lastAdd = handle;
return (
<div>
父:<input type="text" value={name} onChange={ev => setName(ev.target.value)} /> <br />
{/* 如果不用useCallback,输入框输入值的时候,执行了setName方法导致App组件要重新渲染,handle函数也会重新创建,传给子组件的引用地址变了,以至于子组件会也会刷新 */}
<MemoChild handle={handle} />
</div>
)
}
useMemo 的原理
function Child(props){
console.log('Child');
return (
<button >子:{props.data.number}</button>
)
}
let MemoChild=React.memo(Child);// memo:如果你想让一个函数组件有一个功能,如果属性不变,就不要刷新
function App() {
let [number, setNumber] = React.useState(0);
let [name,setName]=React.useState('zhufeng');
// let data={number};
let data=React.useMemo(()=>({number}),[number]);// 每次重新渲染App导致引用地址改变了
return (
<div>
{/* 输入框输入值改变的是APP组件,Child组件不应该渲染,所以需要优化 */}
父:<input type="text" value={name} onChange={ev=>setName(ev.target.value)} /> <br />
{/* 需改进:这时App组件更新,number没变,子组件依然会渲染 */}
{/* 前提:data的值是对象引用数据类型的。如果不用useMemo,输入框输入值的时候,执行了setName方法导致App组件要重新渲染,data数据会重新创建新的对象,传给子组件的引用地址变了,以至于子组件会也会刷新 */}
<MemoChild data={data} />
</div>
)
}
useCallback和useMemo 的简单实现
let hookStates = [];// 保存状态的数组
let hookIndex = 0;//索引
function useMemo(factory, dependencies) {
if (hookStates[hookIndex]) { // 说明不是第一次
let [lastMemo, lastDependencies] = hookStates[hookIndex];
// 判断一下新的依赖数组中的每一项是否跟上次完全相等
let same = dependencies.every((item, index) => item === lastDependencies[index]);
// 没变则用老的
if (same) {
hookIndex++;
return lastMemo;
} else { //只要有一个依赖变量不一样的话
let newMemo = factory();
hookStates[hookIndex++] = [newMemo, dependencies];
return newMemo;
}
} else {// 说明是第一次渲染
let newMemo = factory();
hookStates[hookIndex++] = [newMemo, dependencies];
return newMemo;
}
}
function useCallback(callback, dependencies) {
if (hookStates[hookIndex]) { // 说明不是第一次
let [lastCallback, lastDependencies] = hookStates[hookIndex];
// 判断一下新的依赖数组中的每一项是否跟上次完全相等
let same = dependencies.every((item, index) => item === lastDependencies[index]);
if (same) {// 老依赖和新依赖都相同,则直接返回老的,如果不相同,则返回新的
hookIndex++;
return lastCallback;
} else { //只要有一个依赖变量不一样的话
hookStates[hookIndex++] = [callback, dependencies];
return callback;
}
} else {// 说明是第一次渲染
hookStates[hookIndex++] = [callback, dependencies];
return callback;
}
}
memo的原理 https://blog.csdn.net/attengtiong/article/details/123128554