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

React Hooks封装useConfirmDialog时state存放入参丢失引用问题求解

问题核心原因
  • 闭包陷阱:你把初始化传入的配置存在了useState中,后续外部传入的配置(比如绑定了最新状态的onDeleteGroup函数)不会同步到内部state,导致函数永远是初始化时的版本。
  • 无限重渲染:你调用useConfirmDialog时传入的是字面量配置对象,每次组件渲染都会生成新的对象引用,useEffect监听props依赖时每次都判定为变化,触发setState后又引发组件重渲染,陷入死循环。
可行解决方案

核心思路是用useRef存储最新的外部基础配置,避免通过setState同步外部配置带来的重渲染和闭包问题,state仅存储弹窗开关状态和showConfirmDialog传入的临时覆盖配置。

实现代码

interface IState {
  isDialogOpen: boolean;
  // 仅存储showConfirmDialog传入的临时覆盖配置
  tempDialogProps?: TDialogProps;
}

export const useConfirmDialog = (baseProps?: TDialogProps) => {
  // 用ref保存最新的外部传入基础配置,每次渲染自动更新,无需触发重渲染
  const latestBasePropsRef = useRef<TDialogProps>(baseProps || {});
  latestBasePropsRef.current = baseProps || {};

  const [state, setState] = useState<IState>({
    isDialogOpen: false,
    tempDialogProps: undefined
  });

  const setIsDialogOpen = (isOpen = true) => {
    setState(prev => ({
      ...prev,
      isDialogOpen: isOpen
    }));
  };

  const showConfirmDialog = (tempDialogProps?: TDialogProps) => {
    setState(prev => ({
      ...prev,
      tempDialogProps
    }));
    setIsDialogOpen(true);
  };

  // 合并配置优先级:内置属性 > 临时覆盖配置 > 外部基础配置
  const mergedDialogProps = {
    ...latestBasePropsRef.current,
    ...state.tempDialogProps,
    isOpen: state.isDialogOpen,
    onClose: () => setIsDialogOpen(false)
  };

  return {
    setIsDialogOpen,
    showConfirmDialog,
    dialogProps: mergedDialogProps
  };
};

方案优势

  • 完全解决闭包问题:外部传入的配置(包括onPress等函数)每次渲染都会自动更新到ref中,永远取最新版本,不需要手动同步。
  • 无额外重渲染:无需用useEffect监听外部配置更新,自然不会触发无限重渲染。
  • 兼容原有使用方式:原有调用逻辑不需要任何修改,同时保留了showConfirmDialog临时修改配置的能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 13:54:02