Skip to content
On this page

react使用useMemo对性能的优化

尤大在知乎看见对react Hooks的评价:

其实 React 所谓的性能问题,大部分就是因为在设计层面上把大量的优化责任抛给了开发者,而且这些优化责任是琐碎的,没法通过一个简单的方案去一杆子搞定。由于绝大部分开发者是懒惰的(倾向于用最少的努力做出可以用的结果),这也就导致绝大部分 React 应用的性能并不理想(这里的 “不理想” 指的是没有达到优化的理论上限,不一定是那种用户能感知到的不理想)

使用useMemo性能优化

useMemo主要用来解决使用React hooks产生的无用渲染的性能问题。使用function的形式来声明组件,失去了shouldCompnentUpdate(在组件更新之前)这个生命周期,也就是说我们没有办法通过组件更新前条件来决定组件是否更新。而且在函数组件中,也不再区分mount和update两个状态,这意味着函数组件的每一次调用都会执行内部的所有逻辑,就带来了非常大的性能损耗。

  • 来看看这个案例上性能的缺陷

index.js

jsx
import React,{ useState } from 'react';
import ReactDOM from 'react-dom';

function Example() {
    const [state1, setState1] = useState(new Date().getTime())
    const [state2, setState2] = useState(new Date().getTime())
    return (
        <>
            <button onClick={() => { setState1(new Date().getTime()) }}>设置state1</button>
            <button onClick={() => { setState2(new Date().getTime() + ',state2') }}>设置state2</button>
            <ChildComponent name={state1}>{state2}</ChildComponent>
        </>
    )
}
function ChildComponent({ name, children }) {
    function returnnames(name) {
        console.log("子组件开始render")
        return name + ',render'
    }

    const names = returnnames(name)
    return (
        <>
            <div>{names}</div>
            <div>{children}</div>
        </>
    )
}
ReactDOM.render(<Example />, document.querySelector("#root"))

这时候你会发现在浏览器中点击设置state2按钮ChildComponent的returnnames方法都会执行,结果虽然没变,但是每次都执行,这就是性能的损耗。目前只有子组件,业务逻辑也非常简单,如果是做了业务上的请求,这将产生严重的后果。所以这个问题必须解决。当我们点击设置state2按钮时,ChildComponent的returnnames方法不能执行,只有在点击设置state2按钮时才能执行。

如何解决?

jsx
import React, { useState, useMemo } from "react"
import ReactDOM from 'react-dom';

function Example() {
    const [state1, setState1] = useState(new Date().getTime())
    const [state2, setState2] = useState(new Date().getTime())
    return (
        <>
            <button onClick={() => { setState1(new Date().getTime()) }}>设置state1</button>
            <button onClick={() => { setState2(new Date().getTime() + ',state2') }}>设置state2</button>
            <ChildComponent name={state1}>{state2}</ChildComponent>
        </>
    )
}
function ChildComponent({ name, children }) {
    function returnnames(name) {
        console.log("子组件开始render")
        return name + ',render'
    }

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

ReactDOM.render(<Example />, document.querySelector("#root"))

这时在浏览器中点击一下设置state2按钮ChildComponent的returnnames就不再执行了。也节省了性能的消耗。

useMemo官方文档

React.memo 与useMemo 对比