如何使用 Next.js^9.3 将 cookie 信息从 SignupPage 填充到 Navbar 组件?

How to populate cookies infos from SignupPage to the Navbar component with Next.js^9.3?

2 天以来,我一直在努力实施身份验证。 我使用 Strapi 作为无头 CMS/backend。 我使用 next.js@9.3.4 作为前端。

我从教程中找到了一个名为 nookie 的软件包。 我有一个注册页面,我在其中实现了 nookies,但因为我想显示 用户名link 让用户 logout 退出,我决定将所有内容放在 React context 中(不知道是否这是个好主意。

在我 刷新页面之前一切正常。 cookie 仍然存在 用户名和 link消失

这是注册页面

    import cogoToast from 'cogo-toast';
    import Router from 'next/router';
    import { parseCookies } from 'nookies';
    import styled from 'styled-components';
    import FormStyles from '../components/styles/FormStyles';
    import Title from '../components/Title';
    import { signupUser } from '../lib/api';
    import useForm from '../lib/useForm';
    import { useInfos } from './context/LocalState';
    // import { useState, useEffect } from 'react';

    const Column = styled.div`
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
      gap: 20px;
    `;

    const SignUpPage = () => {
      const { inputs, handleChange, clearForm } = useForm({
        username: 'machin',
        email: 'machin@850g.com',
        password: 'azerty123',
      });

      const { userLogin } = useInfos();
      const isEmpty = !inputs.username || !inputs.email || !inputs.password;

      const handleSubmit = async e => {
        e.preventDefault();
        const res = await signupUser(
          inputs.username,
          inputs.email,
          inputs.password
        );
        userLogin(res);
        clearForm();
      };
      return (
        <Column>
          <FormStyles method="post" onSubmit={handleSubmit}>
            <fieldset>
              <Title title="Se creer un Compte" center />

              {isEmpty && (
                <p className="form-empty">Pense a remplir tous les champs</p>
              )}
              <label htmlFor="username">
                Username
                <input
                  type="text"
                  name="username"
                  value={inputs.username}
                  onChange={handleChange}
                  autoComplete="name"
                />
              </label>
              <label htmlFor="email">
                Email
                <input
                  type="email"
                  name="email"
                  value={inputs.email}
                  onChange={handleChange}
                  autoComplete="email"
                />
              </label>
              <label htmlFor="password">
                Password
                <input
                  type="password"
                  name="password"
                  value={inputs.password}
                  onChange={handleChange}
                  autoComplete="new-password"
                />
              </label>
              {!isEmpty && <button type="submit">Sign Up</button>}
            </fieldset>
          </FormStyles>
        </Column>
      );
    };

    SignUpPage.getInitialProps = ctx => {
      const isAuthenticated = parseCookies(ctx).coookiePapi;
      console.log({ isAuthenticated });

      // When the user is authenticated, don't let the user visit the
      // sign-in and sign-up routes
      if (isAuthenticated && ['/signup', '/signin'].indexOf(ctx.asPath) > -1) {
        if (typeof window !== 'undefined') {
          Router.push('/');
          cogoToast.info("You're already logged papi");
        } else if (ctx.res) {
          ctx.res.writeHead(301, {
            Location: '/',
          });
          ctx.res.end();
        }
      }
      return {};
    };

    export default SignUpPage;

我的 2 个函数来自 React Context

    const userLogin = info => (
    setCookie(null, 'coookiePapi', info.jwt, {
    maxAge: 30 * 24 * 60 * 60,
    path: '/',
    }),
    setUser(info),
    info.jwt
    ? cogoToast.success("great {info.user.username}!")
    : cogoToast.error("Something went wrong"),
    Router.push('/')
    );

    const userLogout = () => (
    destroyCookie(null, 'cookiePapi'),
    Router.push('/'),
    setUser([]),
    cogoToast.success('See you soon')
    );

React 应用上下文将在页面刷新时重置,您需要编写自己的 persistence 逻辑。我不确定你的 setUser 功能是做什么的,但你需要做两件事:

a) 当用户状态改变时在登录时写入存储。我们可以通过一个effect hook来实现(当userState改变时,持久化到localStorage):

useEffect(() => {
  localStorage.setItem('userState', JSON.stringify(userDetails))
}, [userDetails])

b) 更新您的上下文/状态代码以从 localStorage 恢复。例如,

let initialUserState = {}
try {
  initialUserState = JSON.parse(window.localStorage.getItem('userState'))
} catch(e) { // do nothing }
const [userState, setUserState] = useState(initialUserState);

use-persisted-state 简化了这个过程,还为您提供了助手来处理应用内状态和存储同步。

由于您将 localStorage 或 sessionStorage 视为存储,因此您可以有效地脱离全局应用程序上下文,并使用定制的挂钩,例如 useUserState,在需要引用您的组件的内部用户状态。