如何使用 Next.js 仅将一些页面包装在 Context Provider 中?

Posted

技术标签:

【中文标题】如何使用 Next.js 仅将一些页面包装在 Context Provider 中?【英文标题】:How do I only wrap some pages in a Context Provider with Next.js? 【发布时间】:2021-02-19 14:37:40 【问题描述】:

我想在三个页面之间共享数据(这些是网络应用程序的核心),但我也有一堆不关心这些数据的博客页面。我看过的任何地方都建议将 Provider 放在 _app.tsx 文件中。如果我理解正确,如果我将MyApp 与提供者包装在一起,如果有人直接访问www.myurl.com/blog/my-blog-1(来自谷歌),那将导致提供者运行其功能;即使该页面不会调用 useContext

如何在 Provider 中只包装三个页面而忽略博客页面?

例如:

www.myurl.com -> 我希望它使用来自提供者的共享数据 www.myurl.com/my-functionality -> 我希望它使用来自提供者的共享数据 www.myurl.com/profile->我希望它使用来自提供者的共享数据 www.myurl.com/blog/* -> 我不希望它调用身份验证提供程序中的函数

这是我的_app.tsx 的样子:

import  AppProps  from 'next/app'
import '../styles/index.css'

export default function MyApp( Component, pageProps : AppProps) 
  return <Component ...pageProps />

【问题讨论】:

【参考方案1】:

嗯,这是一个有趣的问题。

挑战是 Next 实现基于文件的路由的方式。由于无法为页面组创建包装器,因此您可以做的开箱即用的事情就是将应用程序包装在上下文提供程序中。但这并不能真正解决您的问题。

SOOO...我认为有一个解决方法。如果你希望能够在上下文提供者中包装某组页面,首先需要将基于文件的路由器替换为 react-router。

Andrea Carraro 有一篇关于这个主题的非常有趣的文章。我认为你应该试试这个: https://dev.to/toomuchdesign/next-js-react-router-2kl8

我也会尝试寻找其他解决方案,但请告诉我这对您有用吗。

【讨论】:

感谢您的建议和帮助我思考这个问题。我希望保留基于文件的路由器,因为它是我非常喜欢 Next.js 的地方之一。我最终只是在上下文中添加了最少量的身份验证信息,并没有像我最初打算的那样共享。【参考方案2】:

我对 Next.js 很陌生,正在寻找同样的问题。 也许我们可以只使用useRouter钩子中的pathnamequery,并在我们的Contexts或自定义_app中尝试一些条件

next/router

【讨论】:

【参考方案3】:

有一种解决方法可以使用没有 react-router 的包装器来包装特定路径的组件。 看看这个视频: https://www.youtube.com/watch?v=69-mnojSa0M

该视频向您展示了如何使用嵌套布局包装子路径的组件。创建一个嵌套布局并使用 Context Provider 包装该布局。

【讨论】:

【参考方案4】:

聚会有点晚了,但实际上有一种官方方法可以做到这一点: 使用per page layout。 首先稍微调整一下你的_app.tsx 文件:

import type  ReactElement, ReactNode  from 'react';
import  AppProps  from 'next/app';
import type  NextPage  from 'next';

type NextPageWithLayout = NextPage & 
    getLayout?: (page: ReactElement) => ReactNode;
;

type AppPropsWithLayout = AppProps & 
    Component: NextPageWithLayout;
;
export const App = ( Component, pageProps : AppPropsWithLayout): unknown => 

    // Use the custom layout defined at the page level, if available
    const getLayout = Component.getLayout ?? ((page) => page);

    return getLayout(<Component ...pageProps />);
;

然后在页面组件中编写以下内容:

// DashboardPage.ts that need to have a UserProvider and CompanyProvider
import Layout from '@components/Layout'; // Default Layout that is imported for all the page
import  ReactElement  from 'react';
import  UserProvider  from '@contexts/user';
import  CompanyProvider  from '@contexts/company';

const DashboardPage = (): JSX.Element => 
    return <DashboardContainer />;
;

// Custom Layout to wrap the page within the User and company providers
DashboardPage.getLayout = function getLayout(page: ReactElement) 
    return (
        <Layout title="Dashboard page">
            <UserProvider>
                <CompanyProvider>page</CompanyProvider>
            </UserProvider>
        </Layout>
    );
;

export default DashboardPage;

【讨论】:

嗨,这真的会保留页面之间的上下文值吗?例如。当您登录时,您的UserProvider 中有用户并且您导航到使用相同布局的其他页面,我怀疑用户会留在上下文中,对吗?

以上是关于如何使用 Next.js 仅将一些页面包装在 Context Provider 中?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Next.js 摆脱 redux 包装器中的控制台日志

如何在没有 useMutation 的情况下在 Next.js 中使用 GraphQL 突变

如何使用 next.js 获取客户端 cookie?

如何使用 Next.js 检查自定义服务器中是不是存在页面

如何从 json 中提取数据并在 Next.js 中作为 props 传递

如何使用 Next.js 访问当前在导航中加载的 url 或页面