React新特性-Hooks之useMemo和useCallback(八)

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

系列目录

useMemo的作用

正如第三章中React新特性-memo(三)memo优化函数组件的渲染行为,当传入组件值不变的情况下都不会重新渲染组件,否则组件就会重新渲染。

而useMemo则定义了一段函数逻辑是否重复执行,本质都是利用了同样的算法来判断依赖是否改变,既而判断是否触发特定逻辑。useMemo减少不必要的计算,实现优化。

useMemo的使用

//TestInput.js

import React, { useState } from 'react'
import Button from './Button'
const TestInput = () => {
  const [inputValue, setInputValue] = useState('')
  const [visible,setVisible] = useState(true)
  const onVisible = ()=>{
    setVisible((visible)=>!visible)
  }
  return (
    <div>
      <input value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> {inputValue}
      { visible && <Button onVisible={onVisible}/>}
    </div>
  )
}
export default TestInput

//Button.js
import React,{memo} from 'react'
const Button = (props) => {
  console.log('我被重新渲染了')
  return (
    <div>
      <button onClick={props.onVisible}>点击隐藏</button>
    </div>
  )
}

//结合memo来优化渲染
export default memo(Button)

这里的例子:当input输入的时候函数组件TestInput就会重新渲染,而Button组件并未用到TestInput中的状态但是也会重新,这显然就需要优化。

这里加入export default memo(Button)来做优化。来自动对比传入的props是否会改变。

但是这样还会再次渲染因为传入Button函数组件中的props.onVisible是个函数,当TestInput重新渲染onVisible这个函数也会重新生成,这样引用地址变化就导致对比出新的数据。而我们在class组件中的解决方式是:

{ visible && <Button onVisible={this.onVisible}/>}

class组件中this.onVisible是类中的一个方法函数,所以就不会再次生成新的函数。但是函数组件中就没法做到这一点。所以对下面代码做些改变:

const TestInput = () => {
  //...
  const onVisible = useMemo(() => {
    return () => {
      setVisible((visible) => !visible)
    }
  }, [])
  return (
    <div>
      <input value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> {inputValue}
      {visible && <Button onVisible={onVisible} />}
    </div>
  )
}
//...

useMemouseEffect的语法是有一样的,第一个参数是要执行的逻辑函数,第二个参数是依赖对比变量的数组。如果不传第二个参数就跟useEffect一样,每次渲染都会执行,如果传入空数组只会运行一次。

一般useMemo都会传入第二个参数,不然使用useMemo的意义就不存在了。

useMemo和useEffect执行的时机

useMemouseEffect存在的巨大的差异就是调用时机。useEffect执行的是副作用,所以一定会在渲染之后执行,但useMemo是需要有返回值的,返回值可以直接参与渲染,所以useMemo是在渲染期间完成的。

import React,{useState,useMemo} from 'react'
export default function Counter() {
  const [count, setCount] = useState(0);
  const doubleCount = useMemo(()=>{
    return count * 2;
  },[count])
  return (
    <>
      <h1>count: {count}, doubleCount: {doubleCount}</h1>
      <button onClick={()=>setCount((count)=>count+1)}>增加</button>
    </>
  );
}

随着count的递增,doubleCount也随着变化。而如果是useEffect的话count值就是上一次的count值。这就是和useEffect的差异。

useMemo和useCallback关系

使用过useMemo后再来看useCallback就非常简单了,如果useMemo返回的是个函数,那么就可以使用useCallback来省略顶层的函数。

//使用useMemo实现
const TestInput = () => {
  //...
  const onVisible = useMemo(() => {
    return () => {
      setVisible((visible) => !visible)
    }
  }, [])
  return (
    <div>
      <input value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> {inputValue}
      {visible && <Button onVisible={onVisible} />}
    </div>
  )
}

//使用useCallback实现
const TestInput = () => {
  //...
  const onVisible = useCallback(() => {
    setVisible((visible) => !visible)
  }, [])
  return (
    <div>
      <input value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> {inputValue}
      {visible && <Button onVisible={onVisible} />}
    </div>
  )
}

也就是说useCallback(fn, deps) 相当于 useMemo(() => fn, deps)useMemo返回缓存的变量,useCallback返回缓存的函数。

注意:依赖项数组不会作为参数传给回调函数。


文章作者: jackie chen
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 jackie chen !
评论
 上一篇
React新特性-Hooks之useReducer(九) React新特性-Hooks之useReducer(九)
useReducer是React提供的一个高级Hook,它不像useEffect、useState、useRef等必须的hook一样,没有useReducer我们也可以正常完成需求的开发,但useReducer可以使我们的代码具有更好的可
2019-07-28
下一篇 
React新特性-Hooks之useRef(七) React新特性-Hooks之useRef(七)
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。 系列目录 React新特性-Context(一) React新
2019-07-23
  目录