浅谈Ant pro useMemo和useCallback

前言:先回顾下在hooks诞生之前,我们通过写class 组件的方式开发新组件的,继承是 class 本身的特性,它支持设置 state,会在 state 改变后重新渲染,可以重写一些父类的方法,这些方法会在 React 组件渲染的不同生命周期调用。

特性:只要父组件的状态更新,无论有没有对子组件进行操作,子组件都会进行更新

基于以上class的特性,如果要优化性能就是:使用immutable进行比较,在不相等的时候调用setState;在shouldComponentUpdate中判断前后的props和state,如果没有变化,则返回false来阻止更新。

在hooks出来之后,让函数组件可以做类组件的事,可以有自己的state,可以处理一些副作用,获取ref。但是function 组件不能做继承,react不再区分mount和update两个状态,这意味着函数组件的每一次调用都会执行其内部的所有逻辑,那么会带来较大的性能损耗。useMemo 和useCallback就是解决性能问题的杀手锏。

useMemo和useCallback的区别

useMemouseCallback
参数第一个参数为回调 第二个参数为要依赖的数据第一个参数为回调 第二个参数为要依赖的数据
返回值缓存计算结果的值缓存的函数
应用场景需要计算的状态函数式组件每次任何一个 state 的变化 整个组件都会被重新刷新,一些函数是没有必要被重新刷新的,此时就应该缓存起来,提高性能,和减少资源浪费。

useCallback 也可以理解为 useMemo的语法糖。 useCallback((x) => { log(x) }, [m]) 等价于 useMemo(() => { (x) => { log(x) } }, [m])

主要区别是 useMemo 将调用 fn 函数并返回其结果,而 useCallback 将返回 fn 函数而不调用它
注意: 不要滥用会造成性能浪费,react中减少render就能提高性能,所以这个仅仅只针对缓存能减少重复渲染时使用和缓存计算结果。

useMemo

useMemo 用来返回一个结果值,避免无用方法的调用
如果不用useMemo,无论是修改maxTimes还是typeVal,由于组件的重新渲染,都会触发validateStatus的执行(能够在控制台看到,即使修改val,也会打印);但是这里的validateStatus计算只依赖于maxTimes的值,在typeVal修改的时候,是没有必要再次计算的。

 const validateStatus = (value: string) => {
 	console.log(value, '计算');
    const reg = /^\d*$/;
    if (!reg.test(`${value}`)) {
      return '请填入正整数';
    }
    if (Number(value) > 10 * 1000) {
      return '时间最多不超过10000';
    } else if (Number(value) < 1) {
      return '时间最少不小于1';
    }
    return '';
 };
  ......
  <input value={typeVal} onChange={event => setValue(event.target.value)}/>
  <Row className={styles.tableselect}>
 	{useMemo(() => {
    return (
      <>
        <Row>
          <Col className="ant-col ant-form-item-label">
            <label className="ant-form-item-required" title="设置时间">
              设置时间
            </label>
          </Col>
          <InputNumber
               value={maxTimes}
               onChange={onTimesChange}
               style={{
                 verticalAlign: 'middle',
                 borderBottomRightRadius: 0,
                 borderTopRightRadius: 0,
                 width: 120,
               }}
             />
           </Row>
           <div
              className="ant-input-group-addon  addon-affter"
              style={{
                paddingTop: '2px',
                verticalAlign: 'middle',
                display: 'inline-table',
                lineHeight: '24px',
                height: '32px',
                borderLeft: '0',
              }}
            ></div>
         <Col className="ant-form-item-explain ant-form-item-explain-error valid-error">
           {validateStatusTimes(maxTimes)}
         </Col>
       </>
     );
   }, [maxTimes, onTimesChange])}
 </Row>

上面我们可以看到,使用useMemo来执行计算时,将maxTimes作为依赖值传递进去。这样,就只会在maxTimes改变的时候触发validateStatus执行,在修改typeVal的时候,返回上一次缓存的值,不会执行validateStatusTimes。

useCallback

useCallback 用来返回一个函数,用在父子组件传参或者通用函数封装中
使用场景是:有一个父组件,其中包含子组件,子组件接收一个函数作为props;通常而言,如果父组件更新了,子组件也会执行更新;但是大多数场景下,更新是没有必要的,我们可以借助useCallback来返回函数,然后把这个函数作为props传递给子组件;这样,子组件就能避免不必要的更新。

// 父级调用子级时,在onClick参数上加上useCallback,参数为[],则第一次初始化结束后,不在改变。
const Child = ({ name, onClick}: ChildProps): JSX.Element => {
   console.log('子组件')
   return(
     <>
        <div>我是一个子组件,父级传过来的数据:{name}</div>
         <button onClick={onClick.bind(null, '新的子组件name')}>改变name</button>
     </>
   );
}
const ChildMemo = memo(Child);
 
const Page = (props) => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('Child组件');
  return (
     <>
       <button onClick={(e) => { setCount(count+1) }}>1</button>
       <p>count:{count}</p>
       <ChildMemo name={name} onClick={ useCallback((newName: string) => setName(newName), []) }/>
       {/* useCallback((newName: string) => setName(newName),[]) */}
       {/* 这里使用了useCallback优化了传递给子组件的函数,只初始化一次这个函数,下次不产生新的函数*/}
     </>
  )
}

注意:useMemo、useCallback都是自带闭包的。也就是说,每一次组件的渲染,其都会捕获当前组件函数上下文中的状态(state, props),所以每一次这两种hooks的执行,反映的也都是当前的状态,你无法使用它们来捕获上一次的状态。对于这种情况,我们应该使用ref来访问

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值