React Hook--useMemo

469 阅读3分钟

useMemo

useMemo和useCallback的作用十分类似,只不过它允许你记住任何类型的变量(不只是函数)。传递一个值和依赖项,useMemo函数会返回一个值,只有在依赖项发生改变的时候,才会重新调用此函数,返回一个新的值。useMemo 也能针对传入子组件的值进行缓存优化。

可以理解成useMemo 类似于Vue的计算属性,它会缓存传入的 函数的返回结果,只有当依赖项数组监听的数据发生了变化才会重新计算返回新的结果,否则就取出之前缓存的结果。与Vue不同的是React需要自己配置依赖项。

useMemo产生的原因

import { useState,useEffect,useCallback } from 'react'
const Home = function (props) {
  let isShow=useCallback((arg)=>{
    console.log(666666);
    let age=new Date().getFullYear()-new Date(arg.birth).getFullYear()
    if(arg.sex!="female"||age>32){
      return 'no show';
    }else{
      return 'show';
    }
  },[]);
  let show=isShow(props.person);
  return (
    <div>
      <p>{props.person.name}</p>
      <p>{props.person.birth}</p>
      <p>{props.person.sex}</p>
      <h4>{show}</h4>
    </div>
  )
}
export default function App() {
  let [person, setPerson] = useState({name:'',birth:'',sex:''})
  useEffect(()=>{
    let personarr= [{name:'hyomin',birth:'19890530',sex:'female'},{name:'jessica',birth:'19890418',sex:'female'},{name:'gloria',birth:'19910816',sex:'female'}];
    setPerson(personarr[0]);
  },[]);
  let [msg,changeMsg]=useState('6ara');
  let change=()=>{
    changeMsg("6ara 4ever");
  }
  return (
    <div>
      <h1>App组件</h1>
      <p>{msg}</p>
      <button onClick={change}>change</button>
      <h2>Home组件</h2>
      <Home person={{...person}}></Home>
    </div>
  )
}

2.gif

子组件初次渲染时,传入的name等都是空字符串会运行一次,然后父组件的useEffect运行之后,会重新传入属性给子组件,子组件函数会再次重新运行就导致isShow函数也重新运行了。

但是在父组件刷新其他数据时,传入子组件的属性并没有改变,子组件也重新运行了,isShow函数也重新运行了,其实isShow函数最后计算的结果是相同的,就影响了性能。而useCallback只是让isShow函数没有被重新创建,并不能让整个函数组件不会重新运行,isShow函数就会因为子组件函数会再次重新运行而运行。

useMemo的使用

import {useMemo} from "react"
const memoizedValue = useMemo(() => valueNeededToBeMemoized, dependencies)

useMemo接收一个函数,该函数的返回值就是需要被记住的变量,当useMemo的第二个参数dependencies数组里面的元素的值没有发生变化的时候,memoizedValue使用的就是上一次的值。

import { useState,useEffect } from 'react'
import Des from './Des.jsx';

export default function App() {
  let [person, setPerson] = useState({name:'',birth:'',sex:''})
  useEffect(()=>{
    let personarr= [{name:'hyomin',birth:'19890530',sex:'female'},{name:'jessica',birth:'19890418',sex:'female'},{name:'gloria',birth:'19910816',sex:'female'}];
    setPerson(personarr[0]);
  },[]);
  let [msg,changeMsg]=useState('6ara');
  let change=()=>{
    changeMsg("6ara 4ever");
  }
  return (
    <div>
      <h1>App组件</h1>
      <p>{msg}</p>
      <button onClick={change}>change</button>
      <h2>Des组件</h2>
      <Des person={{...person}}></Des>
    </div>
  )
}



import { useCallback,useMemo } from 'react'

export default function Des(props) {
    console.log(777777);
    let isShow=useCallback((arg)=>{
        console.log(666666);
        let age=new Date().getFullYear()-new Date(arg.birth).getFullYear()
        if(arg.sex!="female"||age>32){
          return 'no show';
        }else{
          return 'show';
        }
      },[]);
      let show=useMemo(()=>{
        return isShow(props.person);
      },[props.person.sex,props.person.birth])
      return (
        <div>
          <p>{props.person.name}</p>
          <p>{props.person.birth}</p>
          <p>{props.person.sex}</p>
          <h4>{show}</h4>
        </div>
      )
}

2.gif

子组件虽然因为父组件重新渲染而重新运行,但是isShow函数并没有重新运行,因为useMemo的依赖项并没有发生变化,useMemo会取出之前的返回值来重新渲染。