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

React日历参会者列表:如何最优追踪每项的操作状态?

React日历参会者操作状态追踪的最佳实践

你用Map来追踪单个参会者的操作状态(重发/删除/错误提示)的思路是合理且符合最佳实践的,不属于反模式。这种方式能精准控制单个参会者的UI状态,避免全局状态污染,也契合React的不可变更新原则。

为什么这个方案可行?

  • 业务数据与UI状态分离:eventAttendees保存参会者核心业务数据,eventAttendeeStatusMap单独管理操作状态,不会修改原始数据结构,后续从后端刷新列表时也不会冲突。
  • 不可更新的优势:React依赖状态的引用变化触发重渲染,使用不可变Map(每次更新返回新实例)能确保只有状态变化的参会者组件触发重渲染,性能更优。

状态更新的具体实现示例

重发邀请的状态处理

const defaultStatus = {
  isResending: false,
  isDeleting: false,
  hasError: false,
  errorMsg: null
};

const handleResendInvite = async (attendeeId) => {
  // 标记为正在重发
  setEventAttendeeStatusMap(prevMap => 
    new Map(prevMap).set(attendeeId, {
      ...prevMap.get(attendeeId) || defaultStatus,
      isResending: true,
      hasError: false,
      errorMsg: null
    })
  );

  try {
    await api.resendInvite(attendeeId);
    // 成功后重置重发状态
    setEventAttendeeStatusMap(prevMap => 
      new Map(prevMap).set(attendeeId, {
        ...prevMap.get(attendeeId),
        isResending: false
      })
    );
  } catch (err) {
    // 失败后标记错误状态
    setEventAttendeeStatusMap(prevMap => 
      new Map(prevMap).set(attendeeId, {
        ...prevMap.get(attendeeId),
        isResending: false,
        hasError: true,
        errorMsg: err.message || '重发邀请失败'
      })
    );
  }
};

删除邀请的状态处理

逻辑和重发类似,只需替换isResending为isDeleting即可:

const handleDeleteInvite = async (attendeeId) => {
  setEventAttendeeStatusMap(prevMap => 
    new Map(prevMap).set(attendeeId, {
      ...prevMap.get(attendeeId) || defaultStatus,
      isDeleting: true,
      hasError: false,
      errorMsg: null
    })
  );

  try {
    await api.deleteInvite(attendeeId);
    // 成功后移除该参会者的状态,并更新参会者列表
    setEventAttendeeStatusMap(prevMap => {
      const newMap = new Map(prevMap);
      newMap.delete(attendeeId);
      return newMap;
    });
    setEventAttendees(prev => prev.filter(a => a.eventAttendeeId !== attendeeId));
  } catch (err) {
    setEventAttendeeStatusMap(prevMap => 
      new Map(prevMap).set(attendeeId, {
        ...prevMap.get(attendeeId),
        isDeleting: false,
        hasError: true,
        errorMsg: err.message || '删除邀请失败'
      })
    );
  }
};

可选优化方案

用普通对象替代Map

如果觉得Map的操作不够直观,可以用普通对象来存储状态,写法更贴近日常React状态更新习惯:

const [eventAttendeeStatusMap, setEventAttendeeStatusMap] = useState({});

// 更新状态的写法
setEventAttendeeStatusMap(prev => ({
  ...prev,
  [attendeeId]: {
    ...prev[attendeeId] || defaultStatus,
    isResending: true
  }
}));

这种方式性能和Map差异极小,适合大多数场景。

封装自定义Hook抽离逻辑

把状态更新逻辑封装成自定义Hook,让组件更简洁:

const useAttendeeStatus = () => {
  const defaultStatus = { isResending: false, isDeleting: false, hasError: false, errorMsg: null };
  const [statusMap, setStatusMap] = useState(new Map());

  const updateStatus = (attendeeId, updates) => {
    setStatusMap(prev => 
      new Map(prev).set(attendeeId, {
        ...prev.get(attendeeId) || defaultStatus,
        ...updates
      })
    );
  };

  const resetStatus = (attendeeId) => {
    setStatusMap(prev => new Map(prev).set(attendeeId, defaultStatus));
  };

  // 清理已不存在的参会者状态
  const syncWithAttendees = (attendees) => {
    setStatusMap(prev => {
      const newMap = new Map();
      attendees.forEach(a => {
        if (prev.has(a.eventAttendeeId)) newMap.set(a.eventAttendeeId, prev.get(a.eventAttendeeId));
      });
      return newMap;
    });
  };

  return { statusMap, updateStatus, resetStatus, syncWithAttendees };
};

在组件中直接调用这个Hook,无需重复编写状态更新逻辑:

const { statusMap, updateStatus, resetStatus, syncWithAttendees } = useAttendeeStatus();

注意事项

  • 当从后端刷新参会者列表时,记得调用状态同步方法(比如上面的syncWithAttendees),清理掉已不存在的参会者状态,避免内存冗余。
  • 错误状态可以提供重试按钮,点击后调用resetStatus重置状态,再触发对应操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 08:55:06