面试题答案
一键面试useCallback作用
useCallback
用于返回一个记忆化的回调函数。它会记住回调函数的引用,只有当依赖项发生变化时,才会返回新的回调函数。这样可以避免在每次渲染时都创建新的函数实例,从而防止因函数引用变化导致的子组件不必要的重新渲染。
useMemo作用
useMemo
用于返回一个记忆化的值。它会记住计算的结果,只有当依赖项发生变化时,才会重新计算并返回新的值。这对于复杂计算很有用,可以避免在每次渲染时都进行重复的计算。
两者区别
- 返回值类型:
useCallback
返回记忆化的函数。useMemo
返回记忆化的值。
- 用途侧重:
useCallback
主要用于防止因函数引用变化导致子组件不必要的重新渲染。useMemo
主要用于避免复杂计算的重复执行。
正确使用以避免不必要重新渲染
- useCallback使用:
- 当子组件依赖于父组件传递的回调函数,且该回调函数在父组件每次渲染时不应该变化时,使用
useCallback
。 - 例如:
import React, { useCallback } from'react'; const ParentComponent = () => { const handleClick = useCallback(() => { // 处理点击逻辑 console.log('Button clicked'); }, []); return ( <ChildComponent onClick={handleClick} /> ); }; const ChildComponent = ({ onClick }) => { return <button onClick={onClick}>Click me</button>; };
- 这里
handleClick
函数只有在依赖项(这里为空数组,表示永远不会变化)发生变化时才会更新,这样ChildComponent
只有在handleClick
引用变化时才会重新渲染。
- 当子组件依赖于父组件传递的回调函数,且该回调函数在父组件每次渲染时不应该变化时,使用
- useMemo使用:
- 当有复杂计算,且希望避免每次渲染都重新计算时,使用
useMemo
。 - 例如:
import React, { useMemo } from'react'; const ParentComponent = () => { const complexValue = useMemo(() => { // 复杂计算逻辑 let result = 0; for (let i = 0; i < 1000000; i++) { result += i; } return result; }, []); return ( <ChildComponent value={complexValue} /> ); }; const ChildComponent = ({ value }) => { return <div>{value}</div>; };
- 这里
complexValue
只有在依赖项(这里为空数组,表示永远不会变化)发生变化时才会重新计算,避免了每次渲染都进行复杂的计算。
- 当有复杂计算,且希望避免每次渲染都重新计算时,使用
复杂计算函数和频繁渲染子组件场景优化
- 对于复杂计算函数:
- 使用
useMemo
来记忆化复杂计算的结果。例如,如果有一个计算两个数组乘积之和的复杂函数:
import React, { useMemo } from'react'; const complexCalculation = (arr1, arr2) => { let sum = 0; for (let i = 0; i < arr1.length; i++) { sum += arr1[i] * arr2[i]; } return sum; }; const ParentComponent = () => { const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; const result = useMemo(() => complexCalculation(arr1, arr2), [arr1, arr2]); return ( <ChildComponent result={result} /> ); }; const ChildComponent = ({ result }) => { return <div>{`The result of complex calculation is: ${result}`}</div>; };
- 这里只有
arr1
或arr2
变化时,才会重新计算result
。
- 使用
- 对于频繁渲染子组件:
- 如果子组件依赖于父组件传递的回调函数,使用
useCallback
来确保回调函数引用稳定。例如,子组件是一个列表项,点击列表项触发一个函数:
import React, { useCallback } from'react'; const ParentComponent = () => { const handleListItemClick = useCallback((item) => { console.log(`Clicked item: ${item}`); }, []); const items = ['item1', 'item2', 'item3']; return ( <ul> {items.map((item) => ( <ChildComponent key={item} item={item} onClick={handleListItemClick} /> ))} </ul> ); }; const ChildComponent = ({ item, onClick }) => { return <li onClick={() => onClick(item)}>{item}</li>; };
- 这样
ChildComponent
不会因为父组件每次渲染导致handleListItemClick
引用变化而不必要地重新渲染。
- 如果子组件依赖于父组件传递的回调函数,使用