阅读本文章须要对 React hooks 中 useState 和 useEffect 有基础的了解。个人这篇文章内有大体介绍 在 React 项目中全量使用 Hooks。javascript
官方文档:html
Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.java
简单来讲就是返回一个函数,只有在依赖项发生变化的时候才会更新(返回一个新的函数)。react
在线代码: Code Sandboxapi
import React, { useState, useCallback } from 'react';
import Button from './Button';
export default function App() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const handleClickButton1 = () => {
setCount1(count1 + 1);
};
const handleClickButton2 = useCallback(() => {
setCount2(count2 + 1);
}, [count2]);
return (
<div> <div> <Button onClickButton={handleClickButton1}>Button1</Button> </div> <div> <Button onClickButton={handleClickButton2}>Button2</Button> </div> </div>
);
}
复制代码
// Button.jsx
import React from 'react';
const Button = ({ onClickButton, children }) => {
return (
<> <button onClick={onClickButton}>{children}</button> <span>{Math.random()}</span> </> ); }; export default React.memo(Button); 复制代码
在案例中能够点击 Button1 和 Button2 两个按钮来查看效果,点击 Button1 的时候只会更新 Button1 后面的内容,点击 Button2 会将两个按钮后的内容都更新。这就表示我在点击 Button2 的时候致使了两个按钮内都从新渲染了。数组
这里或许会注意到
React.memo
这个方法,此方法内会对 props 作一个浅层比较,若是若是 props 没有发生改变,则不会从新渲染此组件。缓存
const a = () => {};
const b = () => {};
a === b; // false
复制代码
上述代码能够看到咱们两个同样的函数倒是不相等的(这是个废话,我相信能看到这的人都知道,因此不作解释了)。bash
const [count1, setCount1] = useState(0);
// ...
const handleClickButton1 = () => {
setCount1(count1 + 1);
};
// ...
return <Button onClickButton={handleClickButton1}>Button1</Button>
复制代码
回头再看上面的 Button
组件都须要一个 onClickButton 的 props ,尽管组件内部有用 React.memo
来作优化,可是咱们声明的 handleClickButton1
是直接定义了一个方法,这也就致使只要是父组件从新渲染(状态或者props更新)就会致使这里声明出一个新的方法,新的方法和旧的方法尽管长的同样,可是依旧是两个不一样的对象,React.memo
对比后发现对象 props 改变,就从新渲染了。dom
const handleClickButton2 = useCallback(() => {
setCount2(count2 + 1);
}, [count2]);
复制代码
上述代码咱们的方法使用 useCallback 包装了一层,而且后面还传入了一个 [count2]
变量,这里 useCallback 就会根据 count2
是否发生变化,从而决定是否返回一个新的函数,函数内部做用域也随之更新。函数
因为咱们的这个方法只依赖了 count2
这个变量,并且 count2
只在点击 Button2 后才会更新 handleClickButton2
,因此就致使了咱们点击 Button1 不从新渲染 Button2 的内容。
import React, { useState, useCallback } from 'react';
import Button from './Button';
export default function App() {
const [count2, setCount2] = useState(0);
const handleClickButton2 = useCallback(() => {
setCount2(count2 + 1);
}, []);
return (
<Button count={count2} onClickButton={handleClickButton2} >Button2</Button>
);
}
复制代码
咱们调整了一下代码,将 useCallback 依赖的第二个参数变成了一个空的数组,这也就意味着这个方法没有依赖值,将不会被更新。且因为 JS 的静态做用域致使此函数内 count2
永远都 0
。
能够点击屡次 Button2 查看变化,会发现 Button2 后面的值只会改变一次。由于上述函数内的 count2
永远都是 0
,就意味着每次都是 0 + 1
,Button 所接受的 count
props,也只会从 0
变成 1
且一直都将是 1
,并且 handleClickButton2
也因没有依赖项不会返回新的方法,就致使 Button 只会因 count
改变而更新一次后就不会被从新渲染。
官方文档:
Pass a “create” function and an array of dependencies. useMemo will only recompute the memoized value when one of the dependencies has changed.
简单来讲就是传递一个建立函数和依赖项,建立函数会须要返回一个值,只有在依赖项发生改变的时候,才会从新调用此函数,返回一个新的依赖值。
useMemo 与 useCallback 很像,根据上述 useCallback 已经能够想到 useMemo 也能针对传入子组件的值进行缓存优化,固然这个值必须是一个对象,若是不是对象而是一些简单类型的如字符串等,那么没更改 React.memo
也能对比出来,下面就直接举个 🌰 对比一下。
// ...
const [count, setCount] = useState(0);
const userInfo = {
// ...
age: count,
name: 'Jace'
}
return <UserCard userInfo={userInfo}> 复制代码
// ...
const [count, setCount] = useState(0);
const userInfo = useMemo(() => {
return {
// ...
name: "Jace",
age: count
};
}, [count]);
return <UserCard userInfo={userInfo}> 复制代码
很明显的上面的 userInfo 每次都将是一个新的对象,不管 count
发生改变没,都会致使 UserCard 从新渲染,而下面的则会在 count
改变后才会返回新的对象。
实际上 useMemo 的做用不止于此,根据官方文档内介绍,它主要的功能应该是:
This optimization helps to avoid expensive calculations on every render.
能够吧一些昂贵的计算逻辑放到 useMemo 中,只有当依赖值发生改变的时候才去更新。
const num = useMemo(() => {
let num = 0;
// 这里使用 count 针对 num 作一些很复杂的计算,当 count 没改变的时候,组件从新渲染就会直接返回以前缓存的值。
return num;
}, [count]);
return <div>{num}</div>
复制代码
也能在不少状况将两种状况结合起来用。
结束。