memo&useMemo&useCallback

useMemo和memo区别是什么?

  • React.memo 是一个高阶组件,它用于避免函数组件进行不必要的重新渲染。 简单来说, useMemo 是用于优化计算操作,而 React.memo 是用于优化渲染。
  • useMemo 是一个 Hook,它用于避免执行昂贵的计算操作。当依赖项改变时, useMemo 将重新计算缓存的值。
  • 如果依赖的数据经常变化,就不用useMemo
  • 如果依赖的数据偶尔变化,就可以用useMemo

问题: 每次修改n1, getN3 就会执行一次

js 复制代码
const Test = function () {
  const [n1, setN1] = useState(0)
  const [n2] = useState(0)

  const click = () => setN1(n1+1)

  const getN3 = () => {
    alert('getN2执行了')
    return n2+100
  }
  
  return (
    <>
      <h1 onClick={click} >{n1}</h1>
      <h1>{getN3()}</h1>
    </>
  )
};

解决: 使用useMemo

js 复制代码
const Test = function () {
  const [n1, setN1] = useState(0)
  const [n2] = useState(0)

  const click = () => setN1(n1+1)

  const n3 = useMemo(() => {
    return n2+100
  }, [n2])
  
  return (
    <>
      <h1 onClick={click} >{n1}</h1>
      <h1>{n3}</h1>
    </>
  )
};

问题: React.memo 在下面情况无法阻止子组件发生渲染

js 复制代码
const Test = function () {
  const [n1, setN1] = useState(0)
  const [n2, setN2] = useState(18)

  const click = () => setN1(n1+1)
  const jack = {age: n2}
  
  return (
    <>
      <h1 onClick={click} >{n1}</h1>
      <Child a={jack} />
    </>
  )
};

let Child = (props) => {
  alert('---render')
  return <h1>child: {props.a.age}</h1>
}
Child = React.memo(Child)

解决: 使用useMemo

js 复制代码
const Test = function () {
  const [n1, setN1] = useState(0)
  const [n2, setN2] = useState(18)

  const click = () => setN1(n1+1)

  const jack = useMemo(() => {
    return {age: n2}
  }, [n2])
  
  return (
    <>
      <h1 onClick={click} >{n1}</h1>
      <Child a={jack} />
    </>
  )
};

let Child = (props) => {
  alert('---render')
  return <h1>child: {props.a.age}</h1>
}
Child = React.memo(Child)

useCallback 和 useMemo 的区别:

  • useCallback 和 useMemo 都是用于优化的 Hook,但它们用于优化的对象不 同。
  • useCallback缓存函数
  • useMemo缓存值
  • 如果依赖值经常变化, 使用useCallback就没有意义

问题: 即使使用了React.memo, 父组件更新, 子组件也会更新

js 复制代码
import { memo, useCallback, useMemo, useState } from "react";

let Child = ({ info }) => {
  console.log("---child render");
  return <h3>child: {info.name}</h3>;
}
// 子组件使用了 memo 进行浅比较
Child = memo(Child) // <<--------

export default function App() {
  const [num, setNum] = useState(0);

  const cb = () => {}

  return (
    <div className="App">
      <h1 onClick={() => setNum(num + 1)}>{num}</h1>
      <Child cb={cb} />
    </div>
  );
}

使用useCallback解决了上面问题

js 复制代码
import { memo, useCallback, useMemo, useState } from "react";

let Child = ({ info }) => {
  console.log("---child render");
  return <h3>child: {info.name}</h3>;
}
// 子组件使用了 memo 进行浅比较
Child = memo(Child) // <<--------

export default function App() {
  const [num, setNum] = useState(0);

  const cb = useCallback(() => {}, []);

  return (
    <div className="App">
      <h1 onClick={() => setNum(num + 1)}>{num}</h1>
      <Child cb={cb} />
    </div>
  );
}

memo有什么用途

shouldComponentUpdate

js 复制代码
class App extends React.Component {
  
  state = {
    count: 1,
  };

  shouldComponentUpdate(nextProps, nextState) {
    if(nextState.count === this.state.count) {
      return false
    }
    return true
  }

  click = () => {
    this.setState({ count: 1 });
  };

  render() {
    console.log('--------render')
    return <button onClick={this.click}>{this.state.count}</button>;
  }
}

PureComponent

PureComponentshouldComponentUpdate中实现了浅比较(比较最外层属性)

js 复制代码
class App extends React.PureComponent {

  state = {
    count: 1,
  };

  click = () => {
    // this.setState({ count: this.state.count+1 });
    this.setState({count: 1})
  };

  render() {
    console.log('--------render')
    return <button onClick={this.click}>{this.state.count}</button>;
  }
}

PureComponent原理

js 复制代码
class App extends React.Component {

  state = {
    count: 1,
  };

  shouldComponentUpdate(nextProps, nextState) {
    const hasNotChange = 
        objEqual(this.props, nextProps) && 
        objEqual(this.state, nextState)
        
    if(hasNotChange === true){
      return false
    }
    return true
  }

  click = () => {
    // this.setState({ count: this.state.count+1 });
    this.setState({count: 1})
  };

  render() {
    console.log('--------render')
    return <button onClick={this.click}>{this.state.count}</button>;
  }
}

// 浅比较
function objEqual(oldObj, newObj) {
  for(let key in newObj) {
    if(oldObj[key] !== newObj[key]) {
      return false
    }
  }
  return true
}

memo

函数组件用memo,实现和 pureComponent一样的功能

问题:

  • 父组件更新, 子组件也触发了更新
  • 但是子组件的props并没有发生变化, 并不需要重新渲染
js 复制代码
import React, { useState, useCallback } from 'react@18';
import { createRoot } from 'react-dom@18/client';

const Test = function () {
  const [count1, setCount1] = useState<number>(0);

  const handleClick = () => {
    setCount1(count1 + 1);
  }

  return <div onClick={handleClick}>
    <h1>click me {count1}</h1>
    <Child />
  </div>;
};
      
let Child = (props) => {
  alert('-----render')
  return <h1>
    {props.count}
  </h1>
}

解决: 使用Reat.memo

js 复制代码
import React, { useState, useCallback } from 'react@18';
import { createRoot } from 'react-dom@18/client';

const Test = function () {
  const [count1, setCount1] = useState<number>(0);

  const handleClick = () => {
    setCount1(count1 + 1);
  }

  return <div onClick={handleClick}>
    <h1>click me {count1}</h1>
    <Child />
  </div>;
};    

let Child = (props) => {
  alert('-----render')
  return <h1>
    {props.count}
  </h1>
}

Child = React.memo(Child) // <---------------

原理

js 复制代码
function memo(FnComponent) {
    return class Memo extends React.PurComponent {
        render(){
            return <>{FnComponent(this.props)}</>
        }
    }
}
相关推荐
rgeshfgreh几秒前
Spring事务传播机制深度解析
java·前端·数据库
Hilaku38 分钟前
我用 Gemini 3 Pro 手搓了一个并发邮件群发神器(附源码)
前端·javascript·github
IT_陈寒39 分钟前
Java性能调优实战:5个被低估却提升30%效率的JVM参数
前端·人工智能·后端
快手技术40 分钟前
AAAI 2026|全面发力!快手斩获 3 篇 Oral,12 篇论文入选!
前端·后端·算法
颜酱42 分钟前
前端算法必备:滑动窗口从入门到很熟练(最长/最短/计数三大类型)
前端·后端·算法
全栈前端老曹1 小时前
【包管理】npm init 项目名后底层发生了什么的完整逻辑
前端·javascript·npm·node.js·json·包管理·底层原理
HHHHHY1 小时前
mathjs简单实现一个数学计算公式及校验组件
前端·javascript·vue.js
boooooooom1 小时前
Vue3 provide/inject 跨层级通信:最佳实践与避坑指南
前端·vue.js
一颗烂土豆1 小时前
Vue 3 + Three.js 打造轻量级 3D 图表库 —— chart3
前端·vue.js·数据可视化
青莲8431 小时前
Android 动画机制完整详解
android·前端·面试