了解 React 之 hooks(二)

了解 React 之 hooks(二)

前言

在前面的文章 了解 React 之 hooks(一) 中介绍了 hooks 的 4 个基础 API(useState、useEffect、useContext、useReducer)。本文主要介绍 hooks 的 3 个性能优化 API,分别为 React.memo、React.useCallback、React.Memo。

React.memo

React.memo 的作用类似于类组件的 shouldComponentUpdate 和 PureComponent,在子组件 props 未更新的时候不渲染子组件,值得注意的是 React.memo 也只能做浅层比较,对于复杂对象只能比较对象的引用。但是可以通过在 React.memo 中传递比较函数来做复杂类型的更新判断。

1. 使用 React.memo 前

App 组件:

import React,{useState} from 'react';
import ReactDOM from 'react-dom';
import Child from './Child';
function App() {
    const [count,setCount]=useState(0);
    return <div onClick={setCount(count+1)}>
        {count}
        <Child name="子组件"/>
    </div>
}
export default App

Child 组件:

import React from 'react';
function Child(props) {
    console.log(props);
    return <div>
        {props.name}
    </div>
}
export default Child

以上案例中当更新 count 时,Child 组件的 props 并未发生变化。如果不做任何处理,每次点击事件执行时,Child 都会重新渲染。这时候就需要 React.memo 来优化。

2. 使用 React.memo 后

import React,{useState} from 'react';
import ReactDOM from 'react-dom';
import Child from './Child';
function App() {
    const [count,setCount]=useState(0);
    return <div onClick={setCount(count+1)}>
        {count}
        <Child name="子组件"/>
    </div>
}
export default App

Child 组件:

import React from 'react';
function Child(props) {
    console.log(props);
    return <div>
        {props.name}
    </div>
}
export default React.memo(Child)

3. React.memo 高级用法

前面说到 React.memo 只是浅层比较,如果要进行深度比较,则需要传入比较函数。

function MyComponent(props) {
  /* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
  /*
  如果把 nextProps 传入 render 方法的返回结果与
  将 prevProps 传入 render 方法的返回结果一致则返回 true,
  否则返回 false
  */
}
export default React.memo(MyComponent, areEqual); 

React.useCallback

在以上案例的基础上,给 App 父组件上添加一个事件,传递给 Child 子组件。

1. 使用 React.useCallback 前

import React,{useState} from 'react';
import ReactDOM from 'react-dom';
import Child from './Child';
function App() {
    const [count,setCount]=useState(0);
    const [title,setTitle]=useState("标题");
    const callback = ()=>{
        setTitle("更改标题")
    }
    return <div onClick={setCount(count+1)}>
        {count}
        <Child name="子组件" callback={callback}/>
    </div>
}
export default App

Child 组件:

import React from 'react';
function Child(props) {
    console.log(props);
    return <div>
        {props.name}
    </div>
}
export default React.memo(Child)

可以发现在执行点击事件的时候,Child 子组件依然每次都渲染了。这就很奇怪了,为啥 props 没有改变,使用了 React.memo。但是还是会重复渲染。

其实在函数组件渲染的时候,函数会重新执行。那么每次创建的 callback 函数也不相同。所以才会导致重新渲染。这时候就需要用到 useCallback。其原理是将函数缓存起来,因此每次创建的就是同一函数,所以不会重复渲染。

2. 使用 React.useCallback 后

import React,{useState,useCallback} from 'react';
import ReactDOM from 'react-dom';
import Child from './Child';
function App() {
    const [count,setCount]=useState(0);
    const [title,setTitle]=useState("标题");
    const callback = ()=>{
        setTitle("更改标题")
    }
    // 通过 useCallback 缓存 callback,并将缓存的 callback 传递给 Child
    const memoizedCallback = useCallback(callback, [])
    return <div onClick={setCount(count+1)}>
        {count}
        <Child name="子组件" callback={memoizedCallback}/>
    </div>
}
export default App

Child 组件:

import React from 'react';
function Child(props) {
    console.log(props);
    return <div>
        {props.name}
    </div>
}
export default React.memo(Child)

3. React.useCallback 高级用法

当函数的参数发生变化时,可以添加在 useCallback 中第二个参数数组中,这样就可以实现每次参数变化时 useCallback 就会重新创建,组件会重新渲染。其特性类似于 useEffect。

React.Memo

前面的两个 API React.memo 和 React.useCallback 主要是为了减少重复渲染。而 React.Memo 则是为了减少重复计算。

1. 使用 React.Memo 前

import React,{useState} from 'react';
import ReactDOM from 'react-dom';
import Child from './Child';
function App() {
    const [count,setCount]=useState(0);
    const getResult = ()=>{
         let result = 0;
         for(let i = 0;i<100000;i++){
            result+=i;
        }
        return result; 
    }
    return <div onClick={setCount(count+getResult())}>
        点此增加{count}
        <Child name="子组件"/>
    </div>
}
export default App

以上案例中每次点击时 getResult 函数都会重复执行。由于 getResult 是一个计算量很大的函数,所以会影响性能。这时候就可以使用 useMemo 做计算结果缓存。

2. 使用 React.Memo 后

import React,{useState} from 'react';
import ReactDOM from 'react-dom';
import Child from './Child';
function App() {
    const [count,setCount]=useState(0);
    const getResult = ()=>{
         let result = 0;
         for(let i = 0;i<100000;i++){
            result+=i;
        }
        return result; 
    }
    const base = useMemo(getResult, []);
    return <div onClick={setCount(count+base)}>
        点此增加{count}
        <Child name="子组件"/>
    </div>
}
export default App

3. React.Memo 高级用法

同样的,当计算函数的参数变化时,也可以添加到 useMemo 的第二个参数数组中,就可能实现当参数变化时进行更新。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值