React学习———React.memo、useMemo和useCallback

React.memo

React.memo是React提供的一个高阶组件,用于优化函数组件的性能,它通过记忆组件的渲染结果,避免在父组件重新渲染时,子组件不必要的重新渲染
React.memo会对组件的props进行浅比较,如果props没有变化,则组件不会重新渲染

基本用法

js 复制代码
import React from 'react'
const MyComponent = (props) => {
	console.log('组件渲染了')
	return <div>{props.value}</div>
}
export default React.memo(MyComponent)

工作原理

  • 默认浅比较:React.memo会对传递给组件的props进行浅比较,如果props没有变化,则跳过重新渲染
  • 自定义比较函数(可选):如果需要更复杂的比较逻辑,可以通过第二个参数传入自定义比较函数

自定义比较函数

js 复制代码
const MyComponent = (props) => {
	console.log('组件渲染了')
	return <div>{props.value}</div>
}
const areEqual = (prevProps, nextProps) => {
	// 自定义比较逻辑
	return prevProps.value === nextProps.value
}
export default React.memo(MyComponent, areEqual)

使用场景

  • 纯函数组件:当组件的渲染结果完全依赖于props,且没有内部状态或副作用时,使用React.memo可以有效避免不必要的渲染
  • 频繁渲染的组件:在父组件频繁更新,但子组件的props变化较少的情况下,使用React.memo可以显著提升性能
  • 大型列表或复杂组件:对于渲染成本较高的组件,使用React.memo可以减少渲染次数,提升应用的整体性能

注意事项

  • 浅比较的局限性:React.memo默认使用浅比较。如果props是复杂的嵌套对象或数组,可能需要自定义比较函数
  • 状态或上下文变化:React.memo只对props的变化敏感,如果组件依赖于状态(state)或上下文(context),这些变化仍会触发重新渲染
  • 过度优化:不要滥用React.memo。因为浅比较和自定义比较函数本身也会带来一定的性能开销

useMemo

useMemo是一个React Hook,用于缓存计算结果,避免在每次渲染时重复执行耗时的计算

特点

  • 用于性能优化,减少不必要的计算
  • 只有依赖项发生变化时,才会重新计算值
  • 返回缓存的计算结果

基本用法

js 复制代码
import React, { useMemo, useState } from 'react';
function ExpensiveCalculation(num){
	console.log('Calculating...');
	return num * 2
}
function App(){
	const [count,setCount] = useState(0)
	const [other, setOther] = useState(0);
	const result = useMemo(() => ExpensiveCalculation(count), [count])
	return (
    <div>
      <p>Result: {result}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <button onClick={() => setOther(other + 1)}>Increment Other</button>
    </div>
  );
}
export default App
  • 第一个参数:回调函数
  • 第二个参数(依赖数组):当依赖项发生变化时,useMemo会重新执行回调函数并返回新的计算结果,如果依赖项没有变化,useMemo会直接返回之前缓存的结果,而不是重新执行回调函数

注意事项

  • useMemo只会缓存计算结果,不会缓存函数本身,如果需要缓存函数本身,使用useCallback
  • 如果依赖项数组为空([]),useMemo的值只会在组件首次渲染时计算一次

useCallback

useCallback是React提供的一个Hook,用于换成函数的引用,避免在组件重新渲染时不必要的重新创建函数

基本用法

js 复制代码
const memozedCallback = useCallback(
	() => {
		// 函数逻辑
	},
	[依赖项]
)
  • 第一个参数:需要缓存的函数
  • 第二个参数(依赖数组):当依赖项发生变化时,useCallback会返回一个新的函数引用;如果依赖项没有变化,则返回缓存的函数引用

为什么需要useCallback

  • 在React中,函数组件每次渲染都会重新创建内部的函数,如果这些函数被传递给子组件或用作依赖项,可能会导致性能问题或不必要的副作用,
  • 例如:子组件的不必要重新渲染;性能浪费,尤其在函数被频繁创建时

使用场景

  • 避免子组件不必要的重新渲染
js 复制代码
import React, { useState, useCallback, useEffect } from 'react';
// ({onClick}):表示从props中解构出onClick的属性
// ({onClick:() => void}):为onClick属性添加类型注解,表示他是一个函数,且没有参数,返回值为void
const Child = React.memo(({onClick}:{onClick:() => void})=>{
	console.log('子组件渲染')
	return <button onClick={onClick}>点击</button>
})

function Parent(){
	const [count,setCount] = useState(0)
	
	const handleClick = useCallback(() => {
		console.log('按钮点击')
	}, [])

	return (
		<div>
			<p>计数:{count}</p>
			<button onClick={() => setCount(count+1)}>增加计数</button>
			<Child onClick={handleClick} />
		</div>
	)
}

1:未使用useCallback时,每次Parent组件重新渲染时,handleClick都会被重新创建,导致Child组件也会重新渲染

2:使用useCallback后:handleClick的引用不会改变,Child组件不会重新渲染

  • 作为依赖项传递给useEffect
js 复制代码
import React, { useState, useCallback, useEffect } from 'react';
function Example(){
	const [count,setCount] = useState(0)
	const logCount = useCallback(() => {
		console.log(`当前计数:${count}`);
	}, [count])
	useEffect(() => {
		logCount()
	}, [logCount]) // 使用 useCallback 缓存的函数作为依赖项
	return <button onClick={() => setCount(count + 1)}>增加计数</button>;
}

1:未使用useCallback时:logCount 每次渲染都会重新创建,导致useEffect每次都重新执行

2:使用useCallback后:logCount只有在count 变化时才会更新,减少不必要的副作用

useCallback和React.memo的区别

特性 useCallback React.memo
作用对象 用于优化函数 用于优化组件
核心功能 避免函数在组件重新渲染时被重新创建 避免组件因props未变化而重新渲染
工作原理 缓存函数引用,只有依赖项变化时才重新创建 浅比较props,决定是否跳过组件渲染
适用场景 当函数被传递给子组件或用作依赖项时 当组件的props很少变化时
性能优化的目标 减少函数的重新创建次数 减少组件的重新渲染次数

useCallback和React.memo结合使用

在实际开发中,经常会被结合使用,尤其是在父组件向子组件传递函数时

useMemo和React.memo的区别

特性 useMemo React.memo
作用 缓存计算结果 优化组件渲染,避免不必要的重新渲染
触发条件 比较依赖项是否变化 比较组件的props是否变化
适用场景 用于函数或计算逻辑的性能优化 用于组件级别的性能优化
返回值 返回缓存的计算结果 返回优化后的组件

总结

  • React.memo 用于组件级别的性能优化,避免子组件不必要的重新渲染
  • useMemo 用于缓存计算结果,适合优化耗时的计算逻辑
  • useCallback 用于缓存函数引用,避免优化子组件接收函数props的场景
相关推荐
Zero1017131 分钟前
【详解pnpm、npm、yarn区别】
前端·react.js·前端框架
inputA12 分钟前
【LwIP源码学习6】UDP部分源码分析
c语言·stm32·单片机·嵌入式硬件·网络协议·学习·udp
海尔辛13 分钟前
学习黑客5 分钟读懂Linux Permissions 101
linux·学习·安全
&白帝&21 分钟前
vue右键显示菜单
前端·javascript·vue.js
Wannaer22 分钟前
从 Vue3 回望 Vue2:事件总线的前世今生
前端·javascript·vue.js
羽球知道42 分钟前
在Spark搭建YARN
前端·javascript·ajax
光影少年1 小时前
vue中,created和mounted两个钩子之间调用时差值受什么影响
前端·javascript·vue.js
真的想上岸啊2 小时前
学习51单片机01(安装开发环境)
嵌入式硬件·学习·51单片机
每次的天空2 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭2 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin