如何通过React Modal输入内容修改Axios POST请求头
问题描述
我正在开发一个React Web应用,要求每次发起POST请求时弹出模态框(Modal),让用户输入审批令牌(Approval Token),并将该令牌添加到请求头中再发送至服务器。
现有代码如下:
Axios请求代码
axios({ url: '/backend/call', method: 'POST' })
Axios请求拦截器代码
axios.interceptors.request.use(function (config) { if (config.method === 'POST') { ApprovalPopup.useApprovalPopup.showPopup(); // 显示包含文本框和提交按钮的模态框 const token = --------; // 如何在用户点击提交后,从模态框中获取此处的令牌? config.headers.approvalToken = token; } return config; });
模态框组件代码
export type IApprovalPopup = { showPopup: () => void; }; const ApprovalPopupContext = createContext<IApprovalPopup>({ showPopup: () => undefined, }); export default function ApprovalPopupProvider({children}: { children: ReactNode }) { const dialogRef = useRef<HTMLDialogElement>(null); const [ticketID, setTicketID] = useState(''); function handleTicketIDEntry(value: string) { setTicketID(value); } function handleSubmit() { // 更新状态并发起后端请求 } function showPopup() { dialogRef.current?.show() } return ( <ApprovalPopupContext.Provider value={{ showPopup }} > <span slot="body"> <div className="ticket-entry"> <Label> Ticket ID</Label> <TextField onTextFieldChange={(event) => handleTicketIDEntry(event.detail.value)} label="Ticket-ID" value={ticketID}> </TextField> </div> <div className="submit-section"> <div className="button"> <Button className="button" onClick={handleSubmit}> Submit </Button> </div> </div> </span> {children} </ApprovalPopupContext.Provider> ); } ApprovalPopupProvider.useApprovalPopup = () => useContext(ApprovalPopupContext);
核心问题:如何从模态框中获取令牌,并在发送请求前将其添加到请求头中?
*补充说明:我可以让第一次请求失败,同时将config传递给模态框,由模态框添加请求头后发起请求,但这样如何确保响应能返回给实际调用组件?调用组件需要更新本地状态、处理自定义错误等,因此需要Promise得到正确解析。
解决方案
核心思路是让请求拦截器返回Promise,等待用户提交令牌后再resolve修改后的请求配置,既能保证请求流程的等待逻辑,又能维持原请求的Promise链完整性,确保调用组件能正常接收响应或错误。
步骤1:修改模态框上下文,支持回调传递
更新IApprovalPopup类型,让showPopup方法可以接收提交和取消的回调函数,用于传递用户输入的令牌或取消操作:
export type IApprovalPopup = { showPopup: (onSubmit: (token: string) => void, onCancel?: () => void) => void; }; const ApprovalPopupContext = createContext<IApprovalPopup>({ showPopup: () => undefined, });
步骤2:更新模态框Provider逻辑
在Provider中保存回调函数,用户提交或取消时触发对应逻辑,同时关闭模态框并清理状态:
export default function ApprovalPopupProvider({children}: { children: ReactNode }) { const dialogRef = useRef<HTMLDialogElement>(null); const [ticketID, setTicketID] = useState(''); const [submitCallback, setSubmitCallback] = useState<((token: string) => void) | null>(null); const [cancelCallback, setCancelCallback] = useState<(() => void) | null>(null); function handleTicketIDEntry(value: string) { setTicketID(value); } function handleSubmit() { if (submitCallback && ticketID.trim()) { submitCallback(ticketID.trim()); dialogRef.current?.close(); resetPopupState(); } } function handleCancel() { cancelCallback?.(); dialogRef.current?.close(); resetPopupState(); } function resetPopupState() { setSubmitCallback(null); setCancelCallback(null); setTicketID(''); } function showPopup(onSubmit: (token: string) => void, onCancel?: () => void) { setSubmitCallback(onSubmit); setCancelCallback(onCancel || (() => {})); dialogRef.current?.showModal(); // 使用showModal确保模态框拦截用户操作 } return ( <ApprovalPopupContext.Provider value={{ showPopup }} > {/* 补充dialog元素,之前代码遗漏 */} <dialog ref={dialogRef}> <span slot="body"> <div className="ticket-entry"> <Label> Ticket ID</Label> <TextField onTextFieldChange={(event) => handleTicketIDEntry(event.detail.value)} label="Ticket-ID" value={ticketID} /> </div> <div className="submit-section"> <div className="button"> <Button className="button" onClick={handleSubmit}> Submit </Button> <Button className="button" onClick={handleCancel} variant="secondary"> Cancel </Button> </div> </div> </span> </dialog> {children} </ApprovalPopupContext.Provider> ); } ApprovalPopupProvider.useApprovalPopup = () => useContext(ApprovalPopupContext);
步骤3:修改Axios拦截器,返回等待Promise
拦截POST请求时,返回Promise等待用户输入,提交后注入令牌并继续请求,取消则抛出错误:
axios.interceptors.request.use(function (config) { if (config.method?.toLowerCase() === 'post') { return new Promise((resolve, reject) => { ApprovalPopup.useApprovalPopup.showPopup( // 用户提交令牌后的逻辑 (token) => { config.headers.approvalToken = token; resolve(config); }, // 用户取消后的逻辑 () => { reject(new Error('用户取消了令牌输入')); } ); }); } return config; });
步骤4:调用组件正常处理结果
原请求的Promise链不受影响,调用组件可正常处理响应和错误:
axios({ url: '/backend/call', method: 'POST' }) .then(response => { // 更新本地状态等操作 console.log('请求成功', response); }) .catch(error => { // 处理错误,包括用户取消的情况 console.error('请求失败', error); });
内容的提问来源于stack exchange,提问作者Saurabh Bhalla
相关产品推荐
相关产品推荐

