React中useCallback和useMemo的原理

为了减少组件渲染,我们可以优化,设置组件的属性变了才重新渲染,如果没变则不渲染。
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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值