Как мне обернуть только некоторые страницы в поставщике контекста с помощью Next.js ?

#reactjs #react-hooks #next.js #use-context

#reactjs #реагирующие хуки #next.js #использовать-context

Вопрос:

У меня есть три страницы, между которыми я хочу обмениваться данными (это ядро веб-приложения), но у меня также есть куча страниц блога, которые не заботятся об этих данных. Везде, где я смотрел, предлагается поместить поставщика в _app.tsx файл. Если я правильно понимаю, что если я свяжусь MyApp с поставщиком, если кто-то сразу перейдет к www.myurl.com/blog/my-blog-1 (от Google), это заставит провайдера запустить свои функции; даже если эта страница не будет вызывать useContext

Как мне обернуть только три страницы в провайдере и оставить страницы блога?

Например:

  • www.myurl.com -> Я хочу, чтобы это использовало общие данные от поставщика
  • www.myurl.com/my-functionality -> Я хочу, чтобы это использовало общие данные от поставщика
  • » rel=»noreferrer»>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:

Немного поздно для вечеринки, но на самом деле есть официальный способ сделать это: использовать макет для каждой страницы. Сначала слегка настройте свой _app.tsx файл:

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

type NextPageWithLayout = NextPage amp; {
    getLayout?: (page: ReactElement) => ReactNode;
};

type AppPropsWithLayout = AppProps amp; {
    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;

  

Комментарии:

1. Привет, действительно ли это сохраняет значения контекста между страницами? Например, когда вы вошли в систему, у вас есть пользователь, UserProvider и вы переходите на другую страницу, использующую тот же макет, я сомневаюсь, что пользователь останется в контексте, не так ли?

2. Для тех, кто сталкивается с этим, это работает! У меня есть многостраничная форма Formik, к которой относится только подкаталог моего приложения. Тег <Formik>, который управляет контекстом, находится в компоненте переноса, который использует мой макет. Я подтвердил, что при переходе между страницами с использованием этого макета контекст сохраняется. Как говорится в документах: This layout pattern enables state persistence because the React component tree is maintained between page transitions. With the component tree, React can understand which elements have changed to preserve state.

Ответ №2:

Что ж, это интересная проблема.

Проблема заключается в том, как Next реализует маршрутизацию на основе файлов. Поскольку нет способа создать оболочку для группы страниц, единственное, что вы можете сделать из коробки, это обернуть приложение в поставщиков контекста. Но это на самом деле не решает вашу проблему.

ОООЧЕНЬ… Я думаю, что есть обходной путь. Если вы хотите иметь возможность обернуть определенную группу страниц в поставщике контекста, сначала вам нужно заменить маршрутизатор на основе файлов на react-router.

На эту тему есть очень интересная статья Андреа Карраро. Я думаю, вам следует попробовать это: https://dev.to/toomuchdesign/next-js-react-router-2kl8

Я также попытаюсь найти другое решение, но дайте мне знать, сработало ли это для вас.

Комментарии:

1. Спасибо за предложение и за то, что помогли мне подумать об этом. Я надеялся сохранить маршрутизатор на основе файлов, поскольку это одна из вещей, которые мне действительно нравятся Next.js . В итоге я просто добавил минимальное количество информации об авторизации в контексте и не делился тем, что изначально предполагал.

Ответ №3:

Существует обходной путь для обертывания компонентов определенного пути с помощью оболочки без react-router. Посмотрите это видео: https://www.youtube.com/watch?v=69-mnojSa0M

В видео показано, как обернуть компоненты вложенного пути вложенным макетом. Создайте вложенный макет и оберните этот макет своим поставщиком контекста.

Ответ №4:

Я новичок в Next.js и ищу тот же вопрос. Может быть, мы можем просто использовать pathname и query из useRouter хука и попробовать некоторые условные обозначения в нашем Contexts или в пользовательском _app

следующий / маршрутизатор

Ответ №5:

Очень поздно отвечать на мой вопрос, но мой подход может помочь кому-то в будущем. Я использовал страницу в качестве оболочки, а для навигации я использовал параметры запроса.


Например

Ответ №6:

Я использую ContextProvider и проверяю страницы пути в _app.js

myContextProvider.js

 import React, { useState } from 'react';
const Context = React.createContext({});

export function myContextProvider({ children }) {
     const [ state1, setState1 ] = useState(true);

     return <Context.Provider value={{ state1, setState1 }}>
          {children} 
     </Context.Provider>;
}

export default Context;
  

_app.js

 import { useRouter } from 'youreFavoRouter';
import { myContextProvider } from './myContextProvider.js';

export default function MyApp({ Component, pageProps }) {
    const router = useRouter();
    
    const isBlogPage = router.pathname.includes('blog');

    return (
        <div>
            {isBlogPage ? (
                <Component {...pageProps} />
            ) : (
                <myContextProvider>
                    <Component {...pageProps} />
                </myContextProvider>
            )}
        </div>
    );
}
  

Теперь все состояния и функции в myContextProvider могут отображаться и использоваться на страницах, которые вы выбираете.
Я надеюсь, что кто-нибудь поможет. 🙂