Next.js 13 Pages路由下Stripe支付成功后React Context丢失问题求助
解决Next.js Pages路由中Stripe支付成功页获取购物篮Context数据的问题
核心原因
Stripe支付完成后的重定向会触发全页面刷新,而React Context的数据仅存储在内存中,刷新后会被清空,所以直接访问Context会拿到空值。
解决方案1:给购物篮数据添加localStorage持久化
1. 修改BasketProvider,同步数据到localStorage
在BasketProvider中,初始化状态时从localStorage读取历史数据,每次购物篮变化时自动写入localStorage:
import { createContext, useContext, useState, useEffect, ReactNode } from 'react'; interface BasketItem { id: string; name: string; quantity: number; // 按需添加其他商品字段 } interface BasketContextType { basket: BasketItem[]; addToBasket: (item: BasketItem) => void; clearBasket: () => void; } const BasketContext = createContext<BasketContextType | undefined>(undefined); export const BasketProvider = ({ children }: { children: ReactNode }) => { // 初始化时读取localStorage中的购物篮数据 const [basket, setBasket] = useState<BasketItem[]>(() => { if (typeof window !== 'undefined') { const saved = localStorage.getItem('basket'); return saved ? JSON.parse(saved) : []; } return []; }); // 购物篮变化时同步到localStorage useEffect(() => { if (typeof window !== 'undefined') { localStorage.setItem('basket', JSON.stringify(basket)); } }, [basket]); const addToBasket = (item: BasketItem) => { setBasket(prev => [...prev, item]); }; const clearBasket = () => { setBasket([]); }; return ( <BasketContext.Provider value={{ basket, addToBasket, clearBasket }}> {children} </BasketContext.Provider> ); }; export const useBasket = () => { const context = useContext(BasketContext); if (!context) { throw new Error('useBasket必须在BasketProvider内部使用'); } return context; };
2. 在支付成功页直接读取Context数据
现在即使页面刷新,BasketProvider会自动从localStorage加载数据,直接用useBasket钩子就能拿到购物篮内容:
// pages/success.tsx import { useBasket } from '../providers/BasketProvider'; import { useEffect } from 'react'; export default function SuccessPage() { const { basket, clearBasket } = useBasket(); // 可选:支付成功后自动清空购物篮 useEffect(() => { clearBasket(); }, [clearBasket]); return ( <div> <h1>支付成功!</h1> <h2>您的订单商品:</h2> <ul> {basket.map(item => ( <li key={item.id}>{item.name} x {item.quantity}</li> ))} </ul> </div> ); }
解决方案2:通过Stripe会话从后端拉取订单数据
如果需要更可靠的订单记录(比如用户清除localStorage的情况),可以在创建Stripe结账会话时,把购物篮数据关联到会话的metadata字段:
// 后端创建结账会话的代码 const checkoutSession: Stripe.Checkout.Session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [/* 商品列表 */], mode: 'payment', metadata: { // 存储订单ID或购物篮JSON字符串(注意字段长度限制) basket: JSON.stringify(basket) }, success_url: `${process.env.NEXT_PUBLIC_BASE_URL}/success?session_id={CHECKOUT_SESSION_ID}` });
然后在支付成功页,通过session_id调用后端接口获取会话详情,提取订单数据:
// pages/success.tsx import { useEffect, useState } from 'react'; interface BasketItem { id: string; name: string; quantity: number; } export default function SuccessPage() { const [orderItems, setOrderItems] = useState<BasketItem[]>([]); useEffect(() => { const sessionId = new URLSearchParams(window.location.search).get('session_id'); if (sessionId) { fetch(`/api/get-stripe-session?session_id=${sessionId}`) .then(res => res.json()) .then(data => { const basket = JSON.parse(data.metadata.basket); setOrderItems(basket); }); } }, []); return ( <div> <h1>支付成功!</h1> <h2>您的订单商品:</h2> <ul> {orderItems.map(item => ( <li key={item.id}>{item.name} x {item.quantity}</li> ))} </ul> </div> ); }
内容的提问来源于stack exchange,提问作者Chris Hunter-Johnson
相关产品推荐
相关产品推荐

