Next.js中如何通过withLayout向Layout传递页面状态Props
解决方案
可以实现,不需要把Layout组件移入页面内部,下面是两种可行的实现方式:
方案一:用React Context传递状态(推荐)
这种方式通过Context在页面组件和Layout组件之间传递状态,不需要修改withLayout的核心逻辑,代码解耦性更好。
- 创建Layout Context
// src/contexts/LayoutContext.tsx import { createContext, useContext, ReactNode } from 'react'; type LayoutContextValue = { isLoading?: boolean; isError?: boolean; }; const LayoutContext = createContext<LayoutContextValue>({}); export const LayoutProvider = ({ children, value }: { children: ReactNode; value: LayoutContextValue; }) => { return <LayoutContext.Provider value={value}>{children}</LayoutContext.Provider>; }; export const useLayoutContext = () => useContext(LayoutContext);
- 修改页面组件,用Provider包裹内容
// src/pages/interactions.tsx import { LayoutProvider } from '../contexts/LayoutContext'; // 其他导入... export const Interactions: PageWithLayout = () => { const [ getInteractions, { loading: isInteractionsLoading, error: isInteractionsError, }, ] = useGetInteractionsLazyQuery({ notifyOnNetworkStatusChange: true, fetchPolicy: "network-only", ssr: false, }); return ( <LayoutProvider value={{ isLoading: isInteractionsLoading, isError: isInteractionsError }}> <Box height="100vh"> {/* 页面内容 */} </Box> </LayoutProvider> ); }; Interactions.withLayout = (page: ReactElement) => { return <Layout>{page}</Layout>; }; export default Interactions;
- 在Layout组件中消费Context
// src/components/Layout.tsx import { useLayoutContext } from '../contexts/LayoutContext'; export const Layout = ({ children }: { children: ReactNode }) => { const { isLoading, isError } = useLayoutContext(); return ( <div className="layout-container"> {/* 根据状态渲染UI */} {isLoading && <div className="loading-indicator">加载中...</div>} {isError && <div className="error-alert">加载失败,请重试</div>} <aside className="sidebar"> {/* 侧边栏内容 */} </aside> <main className="content">{children}</main> </div> ); };
方案二:通过页面元素传递props
这种方式把状态挂载到页面返回的根元素props上,然后在withLayout中提取并传递给Layout。
- 修改页面组件,给根元素添加状态props
// src/pages/interactions.tsx export const Interactions: PageWithLayout = () => { const [ getInteractions, { loading: isInteractionsLoading, error: isInteractionsError, }, ] = useGetInteractionsLazyQuery({...}); // 把状态挂载到根元素的props上 return ( <Box height="100vh" isInteractionsLoading={isInteractionsLoading} isInteractionsError={isInteractionsError} > {/* 页面内容 */} </Box> ); };
- 修改withLayout方法,提取状态并传递给Layout
import React from 'react'; Interactions.withLayout = (page: ReactElement) => { // 从页面元素的props中取出状态 const { isInteractionsLoading, isInteractionsError, ...pageProps } = page.props; // 克隆页面元素,移除额外的状态props(避免传递给Box组件) const cleanedPage = React.cloneElement(page, pageProps); return ( <Layout loading={isInteractionsLoading} error={isInteractionsError} > {cleanedPage} </Layout> ); };
- 确保Layout组件接收对应的props
// src/components/Layout.tsx export const Layout = ({ children, loading, error }: { children: ReactNode; loading?: boolean; error?: boolean; }) => { return ( <div className="layout-container"> {loading && <div>加载中...</div>} {error && <div>出错了...</div>} <aside>侧边栏</aside> <main>{children}</main> </div> ); };
内容的提问来源于stack exchange,提问作者Charles Semaan
相关产品推荐
相关产品推荐

