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)}</>
        }
    }
}
相关推荐
MediaTea几秒前
思考与练习(第四章 程序组成与输入输出)
java·linux·服务器·前端·javascript
BD_Marathon2 分钟前
【JavaWeb】NPM_简介和相关配置
前端·npm·node.js
咸鱼加辣5 分钟前
【前端框架】react
前端·react.js·前端框架
unicrom_深圳市由你创科技6 分钟前
Vue 3 高效开发技巧总结
前端·javascript·vue.js
HIT_Weston8 分钟前
66、【Ubuntu】【Gitlab】拉出内网 Web 服务:Gitlab 配置审视(十)
前端·ubuntu·gitlab
长空任鸟飞_阿康12 分钟前
LangChain 技术栈全解析:从模型编排到 RAG 实战
前端·python·langchain
chilavert31813 分钟前
技术演进中的开发沉思-258 Ajax:自定义事件
前端·ajax·okhttp
南知意-19 分钟前
从零搭建 Live2D 看板娘教程(自建API避墙版)
服务器·前端·vue.js·开源·博客·美化·看板娘
来杯三花豆奶26 分钟前
Vue 2 中 Store (Vuex) 从入门到精通
前端·javascript·vue.js
Lethehong26 分钟前
React构建实时股票分析系统:蓝耘MaaS平台与DeepSeek-V3.2的集成实践
前端·react.js·前端框架·蓝耘mcp·蓝耘元生代·蓝耘maas