React Hook 之 useMemo及 React.memo

一、useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

返回一个 memoized 值。

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

记住,传入useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect的适用范畴,而不是 useMemo

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

以下举例说明:

  1. 父组件
function App() {
  const [name, setName] = useState('名称')
  const [content,setContent] = useState('内容')
  return (
      <>
        <button onClick={() => setName(new Date().getTime())}>name</button>
        <button onClick={() => setContent(new Date().getTime())}>content</button>
        <Button name={name}>{content}</Button>
      </>
  )
}
  1. 子组件
function Button({ name, children }) {
  function changeName(name) {
    console.log('11')
    return name + '改变name的方法'
  }

  const otherName =  changeName(name)
  return (
      <>
        <div>{otherName}</div>
        <div>{children}</div>
      </>

  )
}

熟悉react的同学可以很显然的看出,当我们点击父组件的按钮的时候,子组件的namechildren都会发生变化。
不管我们是改变name或者content的值,我们发现 changeName的方法都会被调用。
是不是意味着 我们本来只想修改content的值,但是由于name并没有发生变化,所以无需执行对应的changeName方法。但是发现他却执行了。 这是不是就意味着性能的损耗,做了无用功。

  1. 优化之后的子组件
function Button({ name, children }) {
  function changeName(name) {
    console.log('11')
    return name + '改变name的方法'
  }

const otherName =  useMemo(()=>changeName(name),[name])
  return (
      <>
        <div>{otherName}</div>
        <div>{children}</div>
      </>

  )
}

export default Button

这个时候我们点击 改变content值的按钮,发现changeName并没有被调用。
但是点击改变name值按钮的时候,changeName被调用了。
所以我们可以使用useMemo方法 避免无用方法的调用,当然一般我们changName里面可能会使用useState来改变state的值,那是不是就避免了组件的二次渲染。达到了优化性能的目的。

二、React.memo
import React, { useState } from 'react'
const Child = props => {
    console.log("render child")
    return (
        <div>
            props count: { props.count }
        </div>
    )
}
const Wrapper = () => {
    const [count, setCount] = useState(0)
    const [id, setId] = useState(0)

    return (
        <div>
            <h2>React Memo</h2>
            <button onClick={() => setId(id + 1)}>render parent</button>
            <button onClick={() => setCount(count + 1)}>change count</button>
            <Child count={count}></Child>
        </div>
    )
}

export default Wrapper

上述例子中,我们每次点击 render parent 按钮,Wrapper组件就会重新渲染,导致Child组件也会重新渲染打印"render child",但实际上,Childprops并未改变,所以不需要render

class component中,我们可以使用 PureComponentshouldComponentUpdate 来控制子组件是否需要渲染.

但在FC中没这些玩意儿该怎么办?

解决方式是用React.memo将子组件 child 包裹起来:

import React, { useState } from 'react'
const Child = props => {
    console.log("render child")
    return (
        <div>
            props count: { props.count }
        </div>
    )
}

const Memo = React.memo(Child)

const Wrapper = () => {
    const [count, setCount] = useState(0)
    const [id, setId] = useState(0)

    return (
        <div>
            <h2>React Memo</h2>
            <button onClick={() => setId(id + 1)}>render parent</button>
            <button onClick={() => setCount(count + 1)}>change count</button>
            <Memo count={count}></Memo>
        </div>
    )
}

这样,只要在我们修改了count的情况下,子组件才会渲染

不仅如此,React.memo还提供了第二参数,一个函数,用来自定义判断前后是否相等,类似

shouldComponentUpdate,只不过返回值相反。

我们把上面的例子改为如果新的count值比老的count的差值值大于等于2Child`才能渲染:

import React, { useState } from 'react'
const Child = props => {
    console.log("render child")
    return (
        <div>
            props count: { props.count }
        </div>
    )
}

const Memo = React.memo(Child, (prev, next) => {
    return (next.count - prev.count) < 2
})
const Wrapper = () => {
    const [count, setCount] = useState(0)
    const [id, setId] = useState(0)

    return (
        <div>
            <h2>React Memo</h2>
            <button onClick={() => setId(id + 1)}>render parent</button>
            <button onClick={() => setCount(count + 1)}>change count</button>
            <Memo count={count}></Memo>
        </div>
    )
}

现在就是点两次change count按钮,才会触发render child

参考:
  1. https://zh-hans.reactjs.org/docs/hooks-reference.html#usememo
  2. https://segmentfault.com/a/1190000018697490
  3. https://zhuanlan.zhihu.com/p/339438975
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值