useCallback
useCallback
防止因为组件重新渲染,导致方法重新创建,起到缓存作用。只有某个依赖项变化了,才重新声明一次。
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
返回一个 memoized 回调函数。
把内联回调函数
及依赖项
数组作为参数传入 useCallback
,它将返回该回调函数的 memoized 版本,该==回调函数仅在某个依赖项改变时才会更新==。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
注意
依赖项数组不会作为参数传给回调函数。虽然从概念上来说它表现为:所有回调函数中引用的值都应该出现在依赖项数组中。未来编译器会更加智能,届时自动创建数组将成为可能。
在 React Hooks 中 useCallback
支持我们缓存某一函数,当且仅当依赖项发生变化时,才更新该函数。这使得我们可以在子组件中配合 useEffect
,实现按需加载。通过 hooks 的配合,使得函数不再仅仅是一个方法,而是可以作为一个值参与到应用的数据流中。
function Parent() {
const [count, setCount] = useState(0);
const [query, setQuery] = useState('keyword');
const getData = useCallback(() => {
const url = `${query}`;
// 请求数据...
console.log(`请求路径为:${url}`);
}, [query]); // 当且仅当 query 改变时 getData 才更新
// 计数值的变化并不会引起 Child 重新请求数据
return (
<>
<h4>计数值为:{count}</h4>
<button onClick={() => setCount(count + 1)}> +1 </button>
<input onChange={(e) => {setQuery(e.target.value)}} />
<Child getData={getData} />
</>
);
}
function Child({
getData
}) {
useEffect(() => {
getData();
}, [getData]); // 函数可以作为依赖项参与到数据流中
return (
// ...
);
}
UserMemo()
useMemo()
是一个内置的 React Hook, 它接受2个参数:一个compute 计算函数和depedencies数组。
const memoizedResult = useMemo(compute, dependencies);
- 在初始渲染期间,
useMemo( compute, dependencies )
调用compute
,记忆计算结果,并将其返回给组件。 - 如果在下一次渲染期间依赖项没有改变,则
useMemo()
不会调用compute
但返回记忆值。 - 但是,如果在重新渲染期间依赖项发生变化,则
useMemo()
调用compute
,记忆新值并返回它。这就是useMemo()
钩子的本质。
useMemo的特点:
第一个参数是()=>value
第二个参数是依赖[m,n]
只有当依赖变化时,才会重新计算出新的value
如果依赖不变,那么就重用之前的value
类似Vue2的computed
注意:如果你的value是一个函数,那么就要写成
useMemo(()=>(x)=>console.log(x))
这是一个返回函数的函数
是不是觉得很难用,那么 就可以使用useCallback
案例
import React, { useState, useMemo } from 'react'
export default function App() {
const [name] = useState('xiaoming')
const [time, setContent] = useState('1664249734848')
return (
<>
<button onClick={() => setContent(new Date().getTime())}>time</button>
<Child name={name}>{time}</Child>
</>
)
}
function Child({ name, children }) {
function changeName(name) {
console.log('change')
return `"name:"${name}`
}
const otherName = ()=>changeName(name)
return (
<>
<div>{otherName}</div>
<div>{children}</div>
</>
)
}
1.当我们点击父组件的time
按钮的时候,发现 changeName
的方法都会被调用。。
2.我们本来只想修改time
的值,但是由于name
并没有发生变化,所以无需执行对应的changeName
方法。但是发现他却执行了。 这是不是就意味着性能的损耗,做了无用功。
下面我们使用useMemo进行优化
import React, { useState, useMemo } from 'react'
export default function App() {
const [name] = useState('xiaoming')
const [time, setContent] = useState('1664249734848')
return (
<>
<button onClick={() => setContent(new Date().getTime())}>time</button>
<Child name={name}>{time}</Child>
</>
)
}
function Child({ name, children }) {
function changeName(name) {
console.log('change')
return `"name:"${name}`
}
const otherName = useMemo(()=>changeName(name),[name])
return (
<>
<div>{otherName}</div>
<div>{children}</div>
</>
)
}
使用useMemo
监听name
的值,避免组件重复渲染