如何在Gatsby网站中保留或重新提供React Context

时间:2019-07-03 17:21:30

标签: reactjs gatsby react-context

我正在将Gatsby用作静态网站生成器。我使用React Context API来存储用户已通过身份验证的信息。

在开发模式下,当我键入任何重定向到404错误页面的URL时,上下文数据将丢失。当我导航到有效页面时,以前登录的用户将不再登录。

我之前从未使用过React Context,所以我不确定该怎么做。那是预期的行为吗?有什么方法可以保留用户特定的React Context?我是否需要从后端重新提供上下文?还是我只是犯了一个错误?最好的行动方针是什么?

我想以某种方式将上下文保留在浏览器中,直到会话超时。后端的会话处理尚未实现。

编辑:我刚刚使用gatsby构建和gatsby服务对其进行了测试。当重定向到404错误页面时,内置的gatsby网站会保留上下文。但是,当导航到完全不同的URL(例如www.google.com)时,上下文仍然丢失。

现在我的问题是:如何在不让用户再次手动登录的情况下为登录信息重新提供上下文? Cookie检查?抱歉,如果我要问一个明显的问题。我从未实现过会话或cookie。

这是我的AuthContextProvider包装器类:

import React from "react";

export const AuthContext = React.createContext();

export class AuthContextProvider extends React.Component {
  state = {
    authenticated: false,
    toggleLogin: () => {},
    userid: null,
  };

  render() {
    return (
      <AuthContext.Provider
        value={{
          authenticated: this.state.authenticated,
          userid: this.state.userid,
          toggleLogin: () => {
            const previousValueState = this.state.authenticated;
            this.setState(state => ({
              authenticated: !previousValueState,
              userid: 2,
            }));
          },
        }}
      >
        {this.props.children}
      </AuthContext.Provider>
    );
  }
}

我将整个应用程序和上下文提供程序一起包装在根目录中:

export default function RootLayout({ children }) {
  return (
    <React.Fragment>
      <Helmet>
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
        />
        <link rel="stylesheet"
              href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,600&display=swap" />
      </Helmet>
      <GoogleReCaptchaProvider reCaptchaKey={recaptchaSiteKey}>
        <ThemeProvider theme={theme}>
          <CssBaseline />
          <AuthContextProvider>
            {children}
          </AuthContextProvider>
        </ThemeProvider>
      </GoogleReCaptchaProvider>
    </React.Fragment>
  );
}

3 个答案:

答案 0 :(得分:1)

React Context是关于向一个或多个子组件提供一些数据,而不必将数据向下传递给中间组件的情况。没有内置的机制可以在页面加载之间持久保存状态,因此您需要为此使用另一种工具。

如果您尚未实现身份验证层,则需要研究其工作原理。有许多策略可以保持该状态,即使只是在使用基于cookie的存储中也是如此。 JWT(JSON Web令牌)是一种流行的方法,它使您可以将已签名的用户和客户端可读数据存储在cookie中,其代价是需要更多的工作来管理到期/续订并具有更大的有效负载。假设这是您采用的方法,则可以执行以下操作:

import React from "react";
import jwt from "jsonwebtoken"; // Add jsonwebtoken via npm/yarn

function getCookieValue(a) {
  var b = document.cookie.match('(^|[^;]+)\\s*' + a + '\\s*=\\s*([^;]+)');
  return b ? b.pop() : '';
}

const AUTH_PUBLIC_KEY = "your JWT public key here"

export const AuthContext = React.createContext();

export class AuthContextProvider extends React.Component {
  state = {
    authenticated: false,
    userid: null,
  };

  componentDidMount() {
    jwt.verify(getCookieValue("session"), AUTH_PUBLIC_KEY, (err, session) => {
      if (!err && session.userid) {
        this.setState({ userid: session.userid, authenticated: true })
      }
    })
  }

  // Important: REMOVE THIS AFTER TESTING/DEV
  toggleLogin = () => {
    this.setState(state => ({
      authenticated: !state.authenticated,
      userid: 2,
    }));
  }

  render() {
    return (
      <AuthContext.Provider
        value={{
          ...this.state,
          toggleLogin: this.toggleLogin,
        }}
      >
        {this.props.children}
      </AuthContext.Provider>
    );
  }
}

这将在安装AuthContextProvider时解析session cookie中的JWT令牌,并使用存储在JWT中的userid值更新状态。

您可能想用此组件包装Gatsby App,可以从gatsby-browser.jsgatsby-ssr.js文件中进行包装(如果不这样做,请在存储库的根目录中创建它们)还没有):

// gatsby-browser.js
import React from "react"
import AuthContextProvider from "components/AuthContextProvider"

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

// gatsby-ssr.js
import React from "react"
export { wrapRootElement } from "./gatsby-browser"

您仍然需要处理JWT令牌的生成(可能是从正在处理身份验证的后端),如果尚未将其持久化在cookie中,则可以从浏览器访问它,您将需要在浏览器处处理该cookie的创建。应用程序生命周期中的相关点。

答案 1 :(得分:1)

我希望这对您或其他人有帮助。下面的博客文章介绍了如何使用gatsby-browser.js将根元素包装在提供程序中,以免在页面更改时将其重置。

https://www.gatsbyjs.org/blog/2019-01-31-using-react-context-api-with-gatsby/

答案 2 :(得分:0)

您有3种可能性:

  1. Web存储又名localStorage或sessionStorage(最简单,最不安全)
  2. 会话cookie(安全,需要后端服务器)
  3. json网络令牌(JWT)(最安全,需要后端服务器)

this blog on dev.to是有关背景信息的绝佳读物。

1。网络存储,例如localStorage

这被认为是最不安全的选项。不要在此处保存个人数据,例如电子邮件地址。永远不要保存诸如信用卡信息之类的敏感信息。

This question描述了如何使用它:

var testObject = { 'one': 1, 'two': 2, 'three': 3 };

// Put the object into storage
localStorage.setItem('testObject', JSON.stringify(testObject));

// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');

console.log('retrievedObject: ', JSON.parse(retrievedObject));

2。 Cookie或会话Cookie

对于Express,您可以使用express-ession。其他Web服务器具有类似的中间件。关键是要按照MDN所述,在Cookie中提供用户信息。

3。 json网络令牌

这类似于Cookie,但使用JSON网络令牌。 @coreyward给出了一个很好的答案。您还可以在this blog post中阅读更多内容。