You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中使用AWS Amplify订阅如何获取state最新值

问题根因

你遇到的是React useEffect常见的闭包陷阱问题:空依赖的useEffect里的回调捕获的是组件首次挂载时的状态快照,所以永远拿不到更新后的todos值;直接把todos加为依赖又会导致每次todos变化时都新增一个订阅,没有清理的话就会触发多次回调。


最优解决方案:使用setState的函数式更新

React的状态更新函数支持传入函数作为参数,这个函数接收的第一个参数就是当前最新的状态值,完全不需要把todos加到依赖数组里,也不会触发重复订阅:

useEffect(() => {
  todoUpdatedSubs.subscribe({
    next: (status: SubscriptionStatus<OnTodoUpdatedSubscription>) => {
      setIsTaskUpdated(true);
      console.log("New Updated SUBSCRIPTION ==> ", status);
      if (!status.value.data.onTodoUpdated.success)
        return console.log("error", status);

      const { id, todo, isCompleted } = status.value.data.onTodoUpdated;
      // 用函数式更新获取最新的todos
      setTodos(prevTodos => {
        const newArr = [...prevTodos];
        // 如果editingIndex也会动态更新,可搭配下面的useRef方案存储最新值
        newArr[editingIndex] = { id, todo, isCompleted };
        return newArr;
      });
    },
  });
}, [])

这个方案不需要修改其他逻辑,适配性最高。


备选方案1:用useRef存储最新状态

如果你的回调里需要用到多个动态变化的状态值,可以用useRef来保存最新的状态快照,每次状态更新时同步更新ref的current值,订阅回调里直接读ref.current就能拿到最新值:

// 定义ref存储最新的todos和editingIndex
const todosRef = useRef(todos);
const editingIndexRef = useRef(editingIndex);

// 状态变化时同步更新ref
useEffect(() => {
  todosRef.current = todos;
  editingIndexRef.current = editingIndex;
}, [todos, editingIndex]);

// 订阅逻辑不变,依赖保持空数组
useEffect(() => {
  todoUpdatedSubs.subscribe({
    next: (status: SubscriptionStatus<OnTodoUpdatedSubscription>) => {
      setIsTaskUpdated(true);
      console.log("New Updated SUBSCRIPTION ==> ", status);
      if (!status.value.data.onTodoUpdated.success)
        return console.log("error", status);

      const newArr = [...todosRef.current];
      console.log("Prev todos", todosRef.current);
      const { id, todo, isCompleted } = status.value.data.onTodoUpdated;
      newArr[editingIndexRef.current] = { id, todo, isCompleted };
      setTodos(newArr);
    },
  });
}, [])

备选方案2:给useEffect加订阅清理函数

如果你一定要把todos加到依赖数组里,只要在useEffect的返回函数里取消之前的订阅,就不会出现重复订阅的问题:

useEffect(() => {
  // 拿到订阅实例
  const subscription = todoUpdatedSubs.subscribe({
    next: (status: SubscriptionStatus<OnTodoUpdatedSubscription>) => {
      setIsTaskUpdated(true);
      console.log("New Updated SUBSCRIPTION ==> ", status);
      if (!status.value.data.onTodoUpdated.success)
        return console.log("error", status);

      const newArr = [...todos];
      console.log("Prev todos", todos);
      const { id, todo, isCompleted } = status.value.data.onTodoUpdated;
      newArr[editingIndex] = { id, todo, isCompleted };
      setTodos(newArr);
    },
  });
  // 组件卸载/依赖变化时取消旧订阅
  return () => subscription.unsubscribe();
}, [todos, editingIndex])

这个方案每次todos变化都会先取消旧的订阅再新增新的订阅,不会有重复回调的问题,但性能略低于前两种方案。


内容的提问来源于stack exchange,提问作者plutolaser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 14:57:06