Tanstack onMutate回调中React状态更新无法触发Modal问题
问题分析与解决方案
核心问题
你遇到的问题根源是模态框状态未在组件间共享:每次调用useModal钩子都会创建一套完全独立的isOpen状态和操作函数。useApproval里调用的handleOpenModal修改的是它自己实例的状态,而Modal组件读取的是另一套独立状态,两者完全无关,自然无法触发模态框显示。
解决方案:用React Context实现状态共享
通过创建全局共享的模态框上下文,让所有需要访问模态框状态的组件共用同一套状态实例。
步骤1:重构useModal钩子,添加Context支持
// hooks/useModal.ts import { createContext, useContext, useCallback, useState, ReactNode } from "react"; // 定义上下文类型 interface ModalContextType { isOpen: boolean; handleOpenModal: () => void; handleCloseModal: () => void; } // 创建上下文,默认值为undefined const ModalContext = createContext<ModalContextType | undefined>(undefined); // 上下文提供者组件 export function ModalProvider({ children }: { children: ReactNode }) { const [isOpen, setIsOpen] = useState(false); const handleOpenModal = useCallback(() => setIsOpen(true), []); const handleCloseModal = useCallback(() => setIsOpen(false), []); return ( <ModalContext.Provider value={{ isOpen, handleOpenModal, handleCloseModal }}> {children} </ModalContext.Provider> ); } // 自定义钩子,用于消费上下文 export function useModal() { const context = useContext(ModalContext); if (!context) { throw new Error("useModal必须在ModalProvider组件内部使用"); } return context; }
步骤2:在父组件中包裹提供者
修改ConnectionOptions组件,用ModalProvider包裹需要共享状态的子组件:
// ConnectionOptions.tsx import { useState, useCallback } from "react"; import { useTrade } from "@/hooks"; import { ModalProvider } from "@/hooks/useModal"; import Modal from "./Modal"; function ConnectionOptions() { const [tokenInAmount, setTokenInAmount] = useState(0); const { onTrade } = useTrade(); // 修复闭包问题:添加tokenInAmount到依赖数组 const handleExecuteTrade = useCallback(() => { onTrade(tokenInAmount); }, [onTrade, tokenInAmount]); return ( <ModalProvider> <Main> <Button onClick={handleExecuteTrade}> Trade </Button> <Modal /> </Main> </ModalProvider> ); }
步骤3:保持原有组件逻辑不变
useApproval、Modal组件的代码无需修改,它们通过useModal钩子消费的是共享上下文里的状态,现在调用handleOpenModal会直接修改Modal组件读取的isOpen状态,模态框就能正常显示了。
额外修复:闭包问题
原代码中handleExecuteTrade的依赖数组遗漏了tokenInAmount,会导致当输入金额变化时,函数仍然使用旧的金额值,已经在上面的代码中修复。
内容的提问来源于stack exchange,提问作者Pavlo Zalutskiy
相关产品推荐
相关产品推荐

