前面了解了 useMemo 与 useCallback 的基本使用,最近了解到 React 中还有一个 memo 的函数,这里做一下对比。
memo
memo 是 React 16.6 发布的一个高阶组件,允许组件在 props 没有改变的情况下跳过重新渲染。
语法
memo(Component, arePropsEqual?)
使用 memo 将组件包装起来,以获得该组件的一个 记忆化 版本。通常情况下,只要该组件的 props 没有改变,这个记忆化版本就不会在其父组件重新渲染时重新渲染。
基本使用
const Greeting = memo((props: { name: string }) => {
console.log("greeting render");
return <div>{`hello ${props.name}`}</div>;
});
使用场景
import React, { memo, useState } from "react";
type IProps = {
name: string;
};
// 改变count会引起 greeting组件的render
const Greeting = (props: { name: string }) => {
console.log("greeting render");
return <div>{`hello ${props.name}`}</div>;
};
const HelloFunction: React.FC<IProps> = (props) => {
const [count, setCount] = useState(0);
const [name, setName] = useState("hello");
const changeName = () => {
setName("world");
}
const changeCount = () => {
setCount(count + 1);
}
return (
<>
<Greeting name={name} />
<button onClick={changeName}>change name</button>
<button onClick={changeCount}>change count</button>
<div>value: {count}</div>
</>
);
}
export default HelloFunction;
使用 memo 包裹组件,当 props 没有状态改变时 Greeting 组件不会重新渲染。
import React, { memo, useState } from "react";
type IProps = {
name: string;
};
// =================================== //
// 改变count不会引起 greeting组件的render了
const Greeting = memo((props: { name: string }) => {
console.log("greeting render");
return <div>{`hello ${props.name}`}</div>;
});
// =================================== //
const HelloFunction: React.FC<IProps> = (props) => {
const [count, setCount] = useState(0);
const [name, setName] = useState("hello");
const changeName = () => {
setName("world");
}
const changeCount = () => {
setCount(count + 1);
}
return (
<>
<Greeting name={name} />
<button onClick={changeName}>change name</button>
<button onClick={changeCount}>change count</button>
<div>value: {count}</div>
</>
);
}
export default HelloFunction;
总结
- 使用 memo 包裹组件,当组件的 props、state 和 context 没有改变时组件不会被重新渲染
- 不执行渲染更新时不会执行子组件代码
- 作用对象为组件并返回一个新组件
- memo 是一个 高阶组件
useMemo
使用场景
import React, { memo, useEffect, useMemo, useState } from "react";
type IProps = {
name: string;
};
// 父组件count发生state改变,子组件也会重新渲染
const Greeting = (props: { names: string[] }) => {
useEffect(() => {
console.log("greeting useEffect");
}, [props.names]);
return <>
<div>
{
props.names.map((item, index) => {
return <div key={index}>{item}</div>;
})
}
</div>
</>;
};
const HelloFunction: React.FC<IProps> = (props) => {
const [count, setCount] = useState(0);
const [name, setName] = useState("hello");
const nameList = () => {
console.log("nameList render");
let names = [];
for (let i = 0; i < 10; i++) {
names.push(`${i}`);
}
return names;
};
const changeName = () => {
setName("world");
}
const changeCount = () => {
setCount(count + 1);
}
return (
<>
<Greeting names={nameList()} />
<button onClick={changeName}>change name</button>
<button onClick={changeCount}>change count</button>
<div>value: {count}</div>
</>
);
}
export default HelloFunction;
useMemo 会缓存计算结果,当依赖项没有改变时不会重新执行计算函数。
import React, { memo, useEffect, useMemo, useState } from "react";
type IProps = {
name: string;
};
// 父组件count发生state改变,子组件也会重新渲染
const Greeting = (props: { names: string[] }) => {
useEffect(() => {
console.log("greeting useEffect");
}, [props.names]);
return <>
<div>
{
props.names.map((item, index) => {
return <div key={index}>{item}</div>;
})
}
</div>
</>;
};
const HelloFunction: React.FC<IProps> = (props) => {
const [count, setCount] = useState(0);
const [name, setName] = useState("hello");
// =================================== //
const nameList = useMemo(() => {
console.log("nameList render");
let names = [];
for (let i = 0; i < 10; i++) {
names.push(`${i}`);
}
return names;
}, [name]);
// =================================== //
const changeName = () => {
setName("world");
}
const changeCount = () => {
setCount(count + 1);
}
return (
<>
<Greeting names={nameList} />
<button onClick={changeName}>change name</button>
<button onClick={changeCount}>change count</button>
<div>value: {count}</div>
</>
);
}
export default HelloFunction;
总结
- 使用 useMemo 包裹计算函数需要返回一个计算结果并会缓存当前函数执行结果,当依赖项没有发生改变时不会执行结算函数
- 不执行渲染更新时会执行子组件代码不会执行 renturn代码
- 作用对象为带返回值的计算函数,需要设置依赖项
- useMemo 是一个 React Hook
useCallback
useCallback 是 useMemo****缓存函数 的一种特殊情况。
使用场景
import React, { memo, useEffect, useMemo, useState } from "react";
type IProps = {
name: string;
};
// 父组件count发生state改变,子组件也会重新渲染
const Greeting = (props: { func: () => void }) => {
useEffect(() => {
console.log("greeting useEffect");
}, [props.func]);
return <>
<button onClick={props.func}>change name</button>
</>;
};
const HelloFunction: React.FC<IProps> = (props) => {
const [count, setCount] = useState(0);
const [name, setName] = useState("hello");
const handle = () => {
console.log("handle");
}
const changeName = () => {
setName("world");
}
const changeCount = () => {
setCount(count + 1);
}
return (
<>
<Greeting func={handle} />
<button onClick={changeName}>change name</button>
<button onClick={changeCount}>change count</button>
<div>value: {count}</div>
</>
);
}
export default HelloFunction;
使用 useCallback 会缓存函数,当依赖项没有发生改变时不会触发子组件渲染
import React, { memo, useCallback, useEffect, useMemo, useState } from "react";
type IProps = {
name: string;
};
// 父组件count发生state改变,子组件也会重新渲染
const Greeting = (props: { func: () => void }) => {
useEffect(() => {
console.log("greeting useEffect");
}, [props.func]);
return <>
<button onClick={props.func}>change name</button>
</>;
};
const HelloFunction: React.FC<IProps> = (props) => {
const [count, setCount] = useState(0);
const [name, setName] = useState("hello");
// =================================== //
const handle = useCallback(() => {
console.log("handle");
}, [name])
// =================================== //
const changeName = () => {
setName("world");
}
const changeCount = () => {
setCount(count + 1);
}
return (
<>
<Greeting func={handle} />
<button onClick={changeName}>change name</button>
<button onClick={changeCount}>change count</button>
<div>value: {count}</div>
</>
);
}
export default HelloFunction;
总结
- 使用 useCallback 包裹函数时会缓存当前函数没有返回值,当依赖项没有发生改变时不会执行结算函数。
- 不执行渲染更新时会执行子组件代码不会执行 renturn代码
- 作用对象为函数,需要设置依赖项
友情提示
见原文:【React】memo、useMemo与useCallback的区别)
本文同步自微信公众号 "程序员小溪" ,这里只是同步,想看及时消息请移步我的公众号,不定时更新我的学习经验。