在使用 hooks 和函数组件编写组件时,第一个要考虑的就是渲染性能。
比如,在函数组件中使用 setState 都会导致组件内部重新渲染: 
当在容器组件手动更新了任何 state 时,容器内部的各个子组件都会重新渲染,为了避免这种情况出现,一般会使用 memo 将函数组件包裹,来达到 class 组件的 pureComponent 的效果:
import React, { memo, useState, useEffect } from 'react'const A = (props) => {console.log('A1')useEffect(() => {console.log('A2')})return <div>A</div>}const B = memo((props) => {console.log('B1')useEffect(() => {console.log('B2')})return <div>B</div>})const Home = (props) => {const [a, setA] = useState(0)useEffect(() => {console.log('start')setA(1)}, [])return <div><A n={a} /><B /></div>}
当我们将 B 组件用 memo 包裹后,状态 a 的更新将不会导致 B 组件重新渲染。
其实仅仅优化这一点还远远不够的,比如:
子组件用到了容器组件的某个引用类型的变量或者函数,那么当容器内部的 state 更新之后,这些变量和函数都会重新赋值,这样就会导致即使子组件使用了 memo 包裹也还是会重新渲染,这个时候我们就需要使用useMemo 和 useCallback了。
useMemo 可以帮我们将变量缓存起来,useCallback 可以缓存回调函数,它们的第二个参数和 useEffect 一样,是一个依赖项数组,通过配置依赖项数组来决定是否更新。
import React, { memo, useState, useEffect, useMemo } from 'react'const Home = (props) => {const [a, setA] = useState(0)const [b, setB] = useState(0)useEffect(() => {setA(1)}, [])const add = useCallback(() => {console.log('b', b)}, [b])const name = useMemo(() => {return b + 'xuxi'}, [b])const A = (props) => {console.log('A1')useEffect(() => {console.log('A2')})return <div>A</div>}const B = memo((props) => {console.log('B1')useEffect(() => {console.log('B2')})return <div>B</div>})return <div><A n={a} /><B add={add} name={name} /></div>}
此时 a 更新后 B 组件不会再重新渲染。
以上几个优化步骤主要是用来优化组件的渲染性能,我们平时还会涉及到获取组件 dom 和使用内部闭包变量的情景,这个时候我们就可以使用 useRef。
useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
function AutoFocusIpt() {const inputEl = useRef(null);const useEffect(() => {// `current` 指向已挂载到 DOM 上的文本输入元素inputEl.current.focus();}, []);return <input ref={inputEl} type="text" />}
