解决NextAuth useSession()延迟致页面加载显示错误会话信息问题
解决方案
1. 利用useSession的状态等待会话就绪
next-auth的useSession会返回status字段,取值包括loading、authenticated、unauthenticated。我们可以等待会话状态明确后再发起请求,避免在session未就绪时调用错误接口,同时减少重复请求。
修改代码如下:
const { data: session, status, update } = useSession() // 解构出会话状态 const getProductsByBrand = async () => { // 会话未加载完成时直接返回,不发起请求 if (status === "loading") return; setLoading(true); const request = new GetProductsRequest() request.setBrandid((brandId as string) || '') const pageReq = new PageRequest() pageReq.setPage(page - 1) pageReq.setPagesize(pageSize) request.setPaging(pageReq) request.setLocale(router.locale || '') let res; if (session?.user?.id) { request.setUserid(session.user.id) res = await ProductService.getProducts(request, getMetaData(session.user.accessToken)) } else { res = await ProductService.getProductsPublic(request, {}) } if (res.getProductsList()?.length > 0) { // 处理数据逻辑 } setLoading(false) } // 将status和session加入依赖,确保会话状态变化时重新请求 useEffect(() => { getProductsByBrand() }, [brandId, session, status])
2. 改用Next.js服务器组件(推荐)
Next.js 14的App Router优先推荐服务器组件,服务器端可以通过getServerSession同步获取会话信息,完全避免客户端的会话延迟问题。
示例代码(App Router服务器组件):
// app/products/[brandId]/page.tsx import { getServerSession } from "next-auth/next" import { authOptions } from "@/app/api/auth/[...nextauth]/route" import ProductService from "@/services/ProductService" export default async function ProductsPage({ params }: { params: { brandId: string } }) { const session = await getServerSession(authOptions) const brandId = params.brandId const page = 1 // 根据实际路由/搜索参数获取页码 const pageSize = 10 const locale = "zh-CN" // 根据实际locale配置获取 const request = new GetProductsRequest() request.setBrandid(brandId) const pageReq = new PageRequest() pageReq.setPage(page - 1) pageReq.setPagesize(pageSize) request.setPaging(pageReq) request.setLocale(locale) let res; if (session?.user?.id) { request.setUserid(session.user.id) res = await ProductService.getProducts(request, getMetaData(session.user.accessToken)) } else { res = await ProductService.getProductsPublic(request, {}) } const products = res.getProductsList() || [] return ( <div> {/* 渲染产品列表 */} {products.map(product => ( <div key={product.getId()}>{product.getName()}</div> ))} </div> ) }
3. 取消重复请求(客户端组件补充优化)
如果必须保留客户端组件,可以使用AbortController在会话状态变化时取消未完成的请求,避免重复请求浪费资源:
const { data: session, status, update } = useSession() const abortControllerRef = useRef<AbortController | null>(null) const getProductsByBrand = async () => { if (status === "loading") return; // 取消之前未完成的请求 if (abortControllerRef.current) { abortControllerRef.current.abort() } const abortController = new AbortController() abortControllerRef.current = abortController setLoading(true) const request = new GetProductsRequest() request.setBrandid((brandId as string) || '') const pageReq = new PageRequest() pageReq.setPage(page - 1) pageReq.setPagesize(pageSize) request.setPaging(pageReq) request.setLocale(router.locale || '') try { let res; if (session?.user?.id) { request.setUserid(session.user.id) res = await ProductService.getProducts(request, getMetaData(session.user.accessToken), { signal: abortController.signal // 传递取消信号 }) } else { res = await ProductService.getProductsPublic(request, {}, { signal: abortController.signal }) } if (res.getProductsList()?.length > 0) { // 处理数据逻辑 } } catch (error) { // 忽略取消请求的错误 if (error.name !== "AbortError") { // 处理其他业务错误 } } finally { setLoading(false) abortControllerRef.current = null } } useEffect(() => { getProductsByBrand() // 组件卸载时取消请求 return () => { if (abortControllerRef.current) { abortControllerRef.current.abort() } } }, [brandId, session, status])
内容的提问来源于stack exchange,提问作者khteh
相关产品推荐
相关产品推荐

