在Gatsby中应该把Context Provider放在哪里?

12

我需要运行一些函数(例如Office UI Fabric React的initializeIcons())和AXIOS调用(例如使用Context API检索已登录用户),仅在网站首次访问时运行,然后将检索到的值存储在React Context中,并使其可用于整个应用程序。

Gatsby将我的页面内容包装在一个Layout中,如下所示:

const IndexPage = () =>
<Layout>
   Body of Index Page...
</Layout>

const AnotherPage = () =>    
<Layout>
   Body of Another Page...
</Layout>

布局如下所示:Layout

const Layout = ({ children }) =>
<>
    <Header /> 
    <main>{children}</main>
    <Footer />
</>

我知道我不能把我的 Context 放在哪里:

  • around the pages (or it will be executed everytime the page is hit, and also not available to the other pages):

    const IndexPage = () =>
    <MyContextProvider>
        <Layout>
           Context Available here
        </Layout>
    </MyContextProvider>
    
    const AnotherPage = () =>    
    <Layout>
        Context NOT available here
    </Layout>
    
  • in the Layout (or it will be executed every time):

    const Layout = ({ children }) =>
    <MyContextProvider>
        <Header /> 
        <main>{children}</main>
        <Footer />
    </MyContextProvider>
    

我想我需要一个根<app>对象来包含我的上下文提供者,但使用Gatsby有什么干净的方式实现呢?

我应该把我的上下文提供者放在哪里?


1
这是来自官方 Gatsby 博客的一篇很棒的博客文章,可能对解决你所需的问题有用。 - Lionel T
1
谢谢@LionelT。这基本上就是我尝试过的,除了localStorage(保存主题没问题,但我认为不能用于已登录的用户)。我可以使用sessionStorage(但那样的话,我需要处理两个不同的用户在同一台PC上连续登录且不关闭浏览器的情况...),我只是希望有一种方法可以“存储”Axios调用的结果并避免再次执行它 - 而不必求助于一些HTML5存储......无论如何,谢谢,我会尽快探讨的。 - Andrea Ligios
2个回答

11

您需要定义一个根布局。与普通布局不同,没有定义“可见”的页面元素,而是隐藏的内容,例如每个页面都需要的ContextProviders、React Helmet、主题等:

RootLayout.jsx:

export default function RootLayout({ children }) {
  return (
    <>
      <Helmet />
        <ThemeProvider theme={theme}>
          <CssBaseline />
          <ContextProvider>
            {children}
          </ContextProvider>
        </ThemeProvider>
    </>
  );
}

Gatsby会通过gatsby-browser.jsgatsby-ssr.js自动隐式调用此根布局,并将其应用于您的每个页面。这两行相同的代码就足够让Gatsby为您处理其余内容。 gatsby-browser.js
export const wrapRootElement = ({ element }) => <RootLayout>{element}</RootLayout>;

gatsby-ssr.js:

export const wrapRootElement = ({ element }) => <RootLayout>{element}</RootLayout>;

摘要:

  • 将上下文提供程序放在根布局中。

参考文献:

  • 我在这里这里提出了相关问题。我在此答案中提供的代码是您和我的问题的解决方案。如果整个应用程序需要此信息,则从React Redux等框架采用的良好编码实践是使用上下文提供程序包装整个应用程序。
  • Lionel T提到的博客文章

好的,回答你其他问题中的那个句子(“没有内置机制来在页面加载之间保持状态,因此您需要使用另一个工具来实现”)表明我需要“手动”实现一些cookie或sessionStorage解决方案来处理Auth部分。至少现在我确定在Gatsby中没有这样的开箱即用的功能,谢谢。 - Andrea Ligios
@AndreaLigios 是的,正确的。我的解决方案是实现JSON Web令牌,以识别经常使用的用户,就像你提到的答案一样。 - EliteRaceElephant
这对我有用,但它会加载我所有的布局两次,这引起了一些问题。 - Edward

0
为了完整性,Gatsby 通过 gatsby-browser.js 提供的 API 来仅运行一次函数是:

onClientEntry

export const onClientEntry = () => {
    console.log("Browser started!")
    // Put here run-only-once functions 
}

在客户端初始渲染时

export const onInitialClientRender = () => {
    console.log("First rendering completed!")
    // Put here run-only-once functions which need rendered output
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接