React Hook useCallback?

本文讲述了如何在React中避免因useEffect和state更新导致的死循环问题,通过useCallback固定getData引用,并演示了自定义hook useRefCallback来管理依赖。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://segmentfault.com/a/1190000020108840
 

死循环

01: Child使用useEffect获取数据,对getData有依赖,于是将其加入依赖列表

02: getData执行时,调用setVal,导致App重新渲染

03: App重新渲染时生成新的getData方法,传给Child

function FatherTest() {
  const [val, setVal] = useState("");

  function getData() {
    setTimeout(() => {
      setVal("new data " + count);
      count++;
    }, 500);
  }
  return <Child val={val} getData={getData} />;
}

function Child({ val, getData }) {
  useEffect(() => {
    getData();
  }, [getData]);

  return <div>{val}</div>;
}

解决死循环

function FatherTest() {
  const [val, setVal] = useState("");

  // 01: getData改变的时候,是需要重新获取数据的。这时就需要通过useCallback来将引用固定住
  const getData = useCallback(() => {
    setTimeout(() => {
      setVal("new data " + count);
      count++;
    }, 500);
  }, []);

  return <Child val={val} getData={getData} />;
}

解决死循环:问题 =》 如果 useCallback需要依赖val,则再次进入死循环 =》 自定义hook

// 自定义hook 
function useRefCallback(fn, dependencies) {
  const ref = useRef(fn);
  // 每次调用的时候,fn 都是一个全新的函数,函数中的变量有自己的作用域
  // 当依赖改变的时候,传入的 fn 中的依赖值也会更新,这时更新 ref 的指向为新传入的 fn
  useEffect(() => {
    ref.current = fn;
  }, [fn, ...dependencies]);

  return useCallback(() => {
    const fn = ref.current;
    return fn();
  }, [ref]);
}

// 调用
  const getData = useRefCallback(() => {
    setTimeout(() => {
      setVal("new data " + count);
      count++;
    }, 500);
  }, [val]);

 

React 中,`useCallback` 是一个用于优化性能的 Hook。它的主要作用是**记忆(缓存)函数引用**,防止每次组件重新渲染时都创建新的函数实例,从而避免不必要的子组件重新渲染或重复计算。 --- ## 🔁 Vue 3 Composition API 中的等价实现 在 Vue 3 的 Composition API 中,并没有直接命名为 `useCallback` 的 API,但我们可以使用以下方式来实现类似的功能: ### ✅ 等价方案:使用 `useMemo` + `() => {}` 或直接使用 `function` / `箭头函数` Vue 的响应式系统中,函数也是普通的 JavaScript 函数,如果你希望缓存一个函数引用以避免重复创建,可以借助 `useMemo` 来达到目的。 --- ## 🧪 示例对比 ### React 版本(使用 useCallback) ```tsx const memoizedCallback = useCallback(() => { doSomething(a, b) }, [a, b]) ``` 上面这段代码的意思是:只有当依赖项 `a` 或 `b` 变化时,才重新创建这个函数。 --- ### Vue 3 Composition API 实现等价逻辑 ```ts import { ref, useMemo } from 'vue' export default { setup() { const a = ref(1) const b = ref(2) const memoizedCallback = useMemo(() => { return () => { console.log('执行操作', a.value, b.value) } }, [a, b]) return { memoizedCallback } } } ``` #### 解释: - `useMemo` 在 Vue 中来自 [`@vueup/vue-use`](https://github.com/vuejs/core/tree/main/packages/vue-use)(社区库),或者你可以自己封装。 - 如果你不想引入第三方库,也可以手动封装一个简单的 `useMemo`: ```ts function useMemo(factory, deps) { const ref = shallowRef() watchEffect(() => { ref.value = factory() }, { flush: 'sync' }) return ref.value } ``` --- ## ⚠️ 注意事项 - Vue 的响应式系统是基于 Proxy/Object.defineProperty 的自动追踪机制,大多数情况下不需要像 React 那样频繁地缓存函数引用。 - **除非你在向子组件传递回调函数且该子组件使用了 `React.memo` 类似的优化策略**,否则在 Vue 中一般不需要刻意“缓存”函数。 --- ## ✅ 更常见的 Vue 做法 如果你只是想监听某些值的变化并执行某个函数,更推荐使用 Vue 原生的 `watch` 或 `watchEffect`: ```ts const a = ref(0) const b = ref(0) watch([a, b], ([newA, newB]) => { console.log('a or b changed:', newA, newB) }) ``` --- ## 💡 总结 | React Hook | Vue 3 等价方案 | 说明 | |----------------|------------------------|------| | `useCallback` | `useMemo(() => fn, deps)` | 缓存函数引用 | | `useCallback`(无依赖) | 直接定义函数即可 | 不需要缓存 | | `useCallback`(有依赖) | `useMemo` + 函数工厂 | 手动缓存 | | 清理副作用 | `onCleanup` in `watchEffect` | 模拟返回清理函数 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值