Next.js _app的getInitialProps返回undefined致JSON解析报错
问题现象
在_app页面通过getInitialProps读取cookies,将侧边栏尺寸值传递给下游组件用于设置元素宽度时,传递值始终为undefined,在AsideLeft组件初始化state执行JSON.parse时报错:Unexpected token u in JSON at position 0。
根因分析
- 异步方法未加
await:App.getInitialProps(appContext)是异步返回Promise的方法,原代码未加await就直接展开返回值,导致返回结构异常,自定义字段无法正确注入组件props - Props传递层级错误:
getInitialProps返回的自定义字段initialAsideLeftHandler和pageProps是平级关系,原代码仅将pageProps展开传给Layout组件,外层的自定义字段根本没有传入下游 - 无兜底逻辑:首次访问页面时
asideLeftHandlercookie尚未生成,parseCookies(req)拿不到对应字段,直接传递undefined给下游组件;JSON.parse(undefined)执行时会先将值转为字符串"undefined",首字符为u,直接触发解析报错 - 重复解析:cookie本身是字符串格式,若上游已经完成JSON解析为对象,下游再次执行
JSON.parse会把对象转成字符串"[object Object]"再解析,同样会触发报错
修复代码
修改_app.tsx
// _app.tsx -> page import App, { AppProps } from 'next/app' // 按你实际使用的parseCookies引入路径调整 import { parseCookies } from 'nookies' // 侧边栏默认尺寸,作为cookie不存在/损坏时的兜底值 const DEFAULT_ASIDE_HANDLER = { x: 0, y: 0, width: 240, height: 0 } function MyApp({ Component, pageProps, initialAsideLeftHandler }: AppProps & { initialAsideLeftHandler: typeof DEFAULT_ASIDE_HANDLER }) { return ( <Layout initialAsideLeftHandler={initialAsideLeftHandler}> <Component {...pageProps} /> </Layout> ); } MyApp.getInitialProps = async (appContext) => { // 必须加await获取真实的pageProps返回值 const pageProps = await App.getInitialProps(appContext); const { req } = appContext.ctx; const cookies = parseCookies(req); let asideHandler = DEFAULT_ASIDE_HANDLER if (cookies.asideLeftHandler) { try { asideHandler = JSON.parse(cookies.asideLeftHandler) } catch (err) { // cookie值格式损坏时回退到默认值 asideHandler = DEFAULT_ASIDE_HANDLER } } return { ...pageProps, initialAsideLeftHandler: asideHandler }; } export default MyApp;
修改AsideLeft组件
// asideLeftHandler.tsx -> component const DEFAULT_ASIDE_HANDLER = { x: 0, y: 0, width: 240, height: 0 } function AsideLeft({ initialAsideLeftHandler = DEFAULT_ASIDE_HANDLER }) { const router = useRouter(); // 上游已经传递解析完成的对象,不需要重复执行JSON.parse const [asideLeftHandler, setAsideLeftHandler] = useState(initialAsideLeftHandler); useEffect(() => { Cookie.set("asideLeftHandler", JSON.stringify(asideLeftHandler), { expires: 7 }); }, [asideLeftHandler]); return ( <Resizeable width={asideLeftHandler.width}> {/* 其余业务代码 */} </Resizeable> ) }
提示:若使用Next.js 13+ App Router模式,
getInitialProps仅在Pages Router下生效,App Router中需在服务端组件调用cookies()方法读取cookie值。
内容的提问来源于stack exchange,提问作者renzCNFT
相关产品推荐
相关产品推荐

