来源:【徐小夕】https://juejin.cn/post/6844904074433789959

    在使用 hooks 和函数组件编写组件时,第一个要考虑的就是渲染性能
    比如,在函数组件中使用 setState 都会导致组件内部重新渲染:
    【React】Hooks 核心 API 使用注意事项 - 图1
    当在容器组件手动更新了任何 state 时,容器内部的各个子组件都会重新渲染,为了避免这种情况出现,一般会使用 memo 将函数组件包裹,来达到 class 组件的 pureComponent 的效果:

    1. import React, { memo, useState, useEffect } from 'react'
    2. const A = (props) => {
    3. console.log('A1')
    4. useEffect(() => {
    5. console.log('A2')
    6. })
    7. return <div>A</div>
    8. }
    9. const B = memo((props) => {
    10. console.log('B1')
    11. useEffect(() => {
    12. console.log('B2')
    13. })
    14. return <div>B</div>
    15. })
    16. const Home = (props) => {
    17. const [a, setA] = useState(0)
    18. useEffect(() => {
    19. console.log('start')
    20. setA(1)
    21. }, [])
    22. return <div><A n={a} /><B /></div>
    23. }

    当我们将 B 组件用 memo 包裹后,状态 a 的更新将不会导致 B 组件重新渲染。

    其实仅仅优化这一点还远远不够的,比如:
    子组件用到了容器组件的某个引用类型的变量或者函数,那么当容器内部的 state 更新之后,这些变量和函数都会重新赋值,这样就会导致即使子组件使用了 memo 包裹也还是会重新渲染,这个时候我们就需要使用useMemo useCallback了。

    useMemo 可以帮我们将变量缓存起来,useCallback 可以缓存回调函数,它们的第二个参数和 useEffect 一样,是一个依赖项数组,通过配置依赖项数组来决定是否更新。

    1. import React, { memo, useState, useEffect, useMemo } from 'react'
    2. const Home = (props) => {
    3. const [a, setA] = useState(0)
    4. const [b, setB] = useState(0)
    5. useEffect(() => {
    6. setA(1)
    7. }, [])
    8. const add = useCallback(() => {
    9. console.log('b', b)
    10. }, [b])
    11. const name = useMemo(() => {
    12. return b + 'xuxi'
    13. }, [b])
    14. const A = (props) => {
    15. console.log('A1')
    16. useEffect(() => {
    17. console.log('A2')
    18. })
    19. return <div>A</div>
    20. }
    21. const B = memo((props) => {
    22. console.log('B1')
    23. useEffect(() => {
    24. console.log('B2')
    25. })
    26. return <div>B</div>
    27. })
    28. return <div><A n={a} /><B add={add} name={name} /></div>
    29. }

    此时 a 更新后 B 组件不会再重新渲染。

    以上几个优化步骤主要是用来优化组件的渲染性能,我们平时还会涉及到获取组件 dom 和使用内部闭包变量的情景,这个时候我们就可以使用 useRef

    useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

    1. function AutoFocusIpt() {
    2. const inputEl = useRef(null);
    3. const useEffect(() => {
    4. // `current` 指向已挂载到 DOM 上的文本输入元素
    5. inputEl.current.focus();
    6. }, []);
    7. return <input ref={inputEl} type="text" />
    8. }