React Native 中的 useCallback
一个简单的比喻:点菜和厨师
想象一下,你是一个顾客(组件),你在一个餐厅里点菜。
没有 useCallback
的情况(普通做法):
- 你每次喊服务员(子组件)过来,哪怕只是问一句“我的菜好了吗?”,你都会重新写一张全新的、一模一样的菜单交给他。
- 服务员(子组件)很困惑:“这张新菜单和上一张完全一样啊?为什么又要给我一份?”
虽然他可能还是会去后厨问一下,但这个“重新写菜单”的动作是多余的,浪费了纸张和精力。
使用 useCallback
的情况(聪明做法):
-
你第一次点菜时,写好了菜单(创建了函数)。
-
你告诉服务员:“这是我的菜单,只要我点的菜不变(依赖项不变),你就一直用这张旧菜单,不用我每次都重写。”
-
这样,只有当你想加菜或退菜(依赖项改变)时,你才会写一张新菜单给他。否则,每次都递给他同一张旧菜单。
服务员(子组件)拿到旧菜单,一看:“哦,这张菜单和上次一模一样,内容根本没变,我就不用再跑去后厨问厨师了,直接告诉你‘还没好’就行了。” 这样就节省了不必要的沟通成本。
在代码里是什么意思?
在 React Native 中,这个“服务员”通常就是你的子组件,特别是用 React.memo
包装过的、被优化过的子组件。
- 函数(菜单): 就是你定义在组件内部的函数,比如
handlePress, onSubmit
。 - 依赖项(点的菜): 就是函数内部使用到的、来自组件外部的变量,比如
state, props
。
为什么要用 useCallback
?
主要目的是性能优化。通过避免在每次渲染时都创建新的函数,可以让依赖于此函数的子组件避免不必要的重新渲染。
语法超级简单
import { useCallback } from 'react';const MyComponent = () => {const [count, setCount] = useState(0);// 没有 useCallback - 每次渲染都创建新函数// const handlePress = () => {// console.log('Pressed!', count);// };// 使用 useCallback - 只有当 count 改变时,才会创建新函数const handlePress = useCallback(() => {console.log('Pressed!', count);}, [count]); // <-- 依赖项数组:count 变了,函数才更新return (<View><Text>Count: {count}</Text>{/* 这个ChildComponent如果用了React.memo,就能从useCallback中受益 */}<ChildComponent onPress={handlePress} /></View>);
};
给小白的关键总结
-
是什么:
useCallback
是一个“记忆函数”的工具。它能把一个函数“缓存”起来。 -
为什么用: 为了防止因为父组件重新渲染,导致传给子组件的函数每次都变成新的,从而触发子组件不必要的渲染。主要是为了性能优化。
-
什么时候用:
-
当你把一个函数作为
prop
传递给一个被React.memo
包装的子组件时。 -
当你把一个函数作为依赖项传给其他
Hook
(比如useEffect
)时。
-
-
怎么用: 用
useCallback
把你的函数包起来,并在第二个参数里告诉它,这个函数依赖了哪些变量。
最后提醒: 不要滥用!不是每个函数都需要 useCallback
。只有当它真的能解决性能问题时才使用。对于简单的组件,用了反而可能增加复杂度,得不偿失。先写没有它的代码,遇到性能问题再考虑它。