memo useCallback useMemo区别与应用

165 阅读2分钟

memo useMemo useCallback 对应的是组件、值、函数的缓存处理

  • memo 用于缓存组件的渲染结果,只有组件的 props 发生改变时才会重新渲染,可以避免不必要的渲染,从而提高性能。(memo(组件))
  • useMemo 用于缓存计算结果(值、对象。。。),只有依赖的值发生改变时才会重新计算,可以避免不必要的计算,从而提高性能。(useMemo(值))
  • useCallback 用于缓存函数引用,可以避免在每次渲染时都创建一个新的函数,从而提高性能。useCallback((函数))

当数据重新赋值时,整个组件会刷新渲染,当数据功能复杂且多,且部分数据无需刷新时,会被强制刷新,造成性能浪费,也可能会产出bug。那么这时候就需要用上useCallback和useMemo来缓存不需要更新的数据,形成memoized值,也就是缓存的值。memo则是用于子组件不重新渲染

什么都没有使用的情况下 Button点击会触发Child渲染

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn = () => {
    setNum(num+1)
  }
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child />
    </div>)
}

const Child =() => {
  console.log('child load')
  return (
      <Button>child text</Button>
  )
}
export default Parent

memo 点击Button Child不再重复渲染

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn = () => {
    setNum(num+1)
  }
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child />
    </div>)
}

const Child = memo(() => {
  console.log('child load')
  return (
      <Button>child text</Button>
  )
})

memo失效 点击Button Child又重复渲染

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn = () => {
    setNum(num+1)
  }
  const clickBtn1 = () => {
    setNum1(num1+1)
  }
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child call={clickBtn1} />
    </div>)
}

const Child = memo((props: any) => {
  console.log('child load')
  return (
      <Button onClick={props.call}>child text</Button>
  )
})

memo与useCallback结合使用 Child不再重复渲染

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn1 = useCallback(() => {
    setNum1(num1+1)
  },[num1])
  const clickBtn = useCallback(() => {
    setNum(num+1)
  },[num])
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child call={clickBtn1} />
    </div>)
}

const Child = memo(({call}: any) => {
  console.log('child load')
  return (
      <Button onClick={call}>child text</Button>
  )
})

传参给子组件 Button点击 Child会跟着渲染

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn = () => {
    setNum(num+1)
  }
  const clickBtn1 = () => {
    setNum1(num1+1)
  }
  const mockData = () => ({
    newNum: num1 
  })
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child num={mockData.newNum} />
    </div>)
}

const Child = memo((num}:any) => {
  console.log('child load')
  return (
    <Button onClick={() => {}}>child text--{num}</Button>
  )
})

传参给子组件 Button点击 Child不会跟着渲染

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn = () => {
    setNum(num+1)
  }
  const clickBtn1 = () => {
    setNum1(num1+1)
  }
  const mockData = useMemo(() => ({
    newNum: num1 
  }),[num1])
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child num={mockData.newNum} />
    </div>)
}

const Child = memo((num}:any) => {
  console.log('child load')
  return (
    <Button onClick={() => {}}>child text--{num}</Button>
  )
})

更改一下 Button点击 Child会跟着渲染

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn = () => {
    setNum(num+1)
  }
  const clickBtn1 = () => {
    setNum1(num1+1)
  }
  const mockData = useMemo(() => ({
    newNum: num1 
  }),[num1])
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child num={mockData.newNum} call={clickBtn1}/>
    </div>)
}

const Child = memo((call,num}:any) => {
  console.log('child load')
  return (
    <Button onClick={call}>child text--{num}</Button>
  )
})

这时候函数也要更改啦

const Parent = ()=> {
  const [num, setNum] = useState(0)
  const [num1, setNum1] = useState(0)
  const clickBtn = () => {
    setNum(num+1)
  }
  const clickBtn1 = useCallback(() => {
    setNum1(num1+1)
  },[num1])
  const mockData = useMemo(() => ({
    newNum: num1 
  }),[num1])
  return (
    <div>
      <div>{num}</div>
      <Button onClick={clickBtn} >+1</Button>
      <Child num={mockData.newNum} call={clickBtn1}/>
    </div>)
}

const Child = memo((call,num}:any) => {
  console.log('child load')
  return (
    <Button onClick={call}>child text--{num}</Button>
  )
})

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)