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)}</>
        }
    }
}
相关推荐
步步为营DotNet1 小时前
深度解析CancellationToken:.NET中的优雅取消机制
java·前端·.net
一位搞嵌入式的 genius2 小时前
从 ES6 到 ESNext:JavaScript 现代语法全解析(含编译工具与实战)
前端·javascript·ecmascript·es6
linweidong4 小时前
C++ 模块化编程(Modules)在大规模系统中的实践难点?
linux·前端·c++
leobertlan7 小时前
2025年终总结
前端·后端·程序员
子兮曰8 小时前
OpenClaw架构揭秘:178k stars的个人AI助手如何用Gateway模式统一控制12+通讯频道
前端·javascript·github
百锦再9 小时前
Reactive编程入门:Project Reactor 深度指南
前端·javascript·python·react.js·django·前端框架·reactjs
莲华君9 小时前
React快速上手:从零到项目实战
前端·reactjs教程
百锦再9 小时前
React编程高级主题:测试代码
android·前端·javascript·react.js·前端框架·reactjs
易安说AI9 小时前
Ralph Loop 让Claude无止尽干活的牛马...
前端·后端
失忆爆表症11 小时前
05_UI 组件库集成指南:Shadcn/ui + Tailwind CSS v4
前端·css·ui