面试题答案
一键面试使用 useCallback
和 useMemo
优化动态列表性能
-
useCallback
优化点击事件回调- 在 React 函数组件中,当动态列表项绑定点击事件时,使用
useCallback
来包裹事件处理函数。 - 示例代码如下:
import React, { useCallback, useState } from'react'; const MyList = ({ data }) => { const [selectedItem, setSelectedItem] = useState(null); const handleClick = useCallback((item) => { setSelectedItem(item); }, []); return ( <ul> {data.map((item) => ( <li key={item.id} onClick={() => handleClick(item)}> {item.name} </li> ))} </ul> ); }; export default MyList;
- 原理:
useCallback
返回一个记忆化的回调函数。只有当依赖数组中的值发生变化时,才会重新创建这个回调函数。在上述代码中,依赖数组为空[]
,意味着只要组件渲染,handleClick
函数就不会改变。这样,当列表项重新渲染时,由于点击事件回调函数没有变化,就不会触发不必要的重新渲染。
- 在 React 函数组件中,当动态列表项绑定点击事件时,使用
-
useMemo
优化列表项数据计算- 如果列表项的数据需要进行一些复杂计算,且依赖于组件内部的
state
或父组件传递的props
,可以使用useMemo
来缓存计算结果。 - 示例代码如下:
import React, { useCallback, useMemo, useState } from'react'; const MyList = ({ data }) => { const [filterText, setFilterText] = useState(''); const filteredData = useMemo(() => { return data.filter((item) => item.name.includes(filterText)); }, [data, filterText]); const handleClick = useCallback((item) => { setFilterText(item.name); }, []); return ( <div> <input type="text" value={filterText} onChange={(e) => setFilterText(e.target.value)} /> <ul> {filteredData.map((item) => ( <li key={item.id} onClick={() => handleClick(item)}> {item.name} </li> ))} </ul> </div> ); }; export default MyList;
- 原理:
useMemo
会在其依赖数组中的值发生变化时,重新计算并返回缓存的值。在上述代码中,只有当data
或filterText
发生变化时,filteredData
才会重新计算,避免了不必要的重复计算,提升了性能。
- 如果列表项的数据需要进行一些复杂计算,且依赖于组件内部的
useCallback
和 useMemo
的区别
- 返回值类型
useCallback
返回一个记忆化的回调函数,主要用于缓存函数引用,避免函数重新创建导致的不必要渲染。useMemo
返回一个记忆化的值,用于缓存复杂计算的结果,避免重复计算。
- 应用场景
useCallback
适用于需要将函数作为 prop 传递给子组件,且希望在父组件重新渲染时保持函数引用不变的场景,如动态列表的点击事件处理函数。useMemo
适用于需要进行复杂计算,且计算结果依赖于某些变量,希望避免不必要的重复计算的场景,如动态列表数据的过滤、排序等计算。