如何在next.js中为用户身份验证全局状态使用zustand 13.4.9

2admgd59  于 2023-08-04  发布在  其他
关注(0)|答案(1)|浏览(336)

我在我的Next.js 13.4.9应用程序中有以下代码(使用应用程序路由器),我不确定如何有效地使用zustand来管理全局auth状态。
zustand商店:

// /src/store/AuthStore.ts

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

type User = {
    token: string | null;
    isAuthenticated: boolean;
};
  
type AuthActions = {
    login: (token: string) => void;
    logout: () => void;
};

const useAuthStore = create<User & AuthActions>()(
    persist((set, get) => ({
        token: null,
        isAuthenticated: false,
        login: token => set({ token, isAuthenticated: true }),
        logout: () => set({ token: null, isAuthenticated: false })
      }),
      { name: 'auth', getStorage: () => localStorage }
    )
);

export default useAuthStore;

字符集
注册页面:

// /app/register/page.tsx

"use client";

import { FormEvent, FormEventHandler, useState } from "react";
import Link from "next/link";
import { DuplicateUserError } from '@/lib/exceptions/DuplicateUserError';
import useAuthStore from '@/store/AuthStore';
import Error from "@/app/error";
import styles from "./page.module.scss";

const Register: React.FC = (): JSX.Element => {
  const [error, setError] = useState<Error | null>(null);
  const login = useAuthStore(state => state.login);

  const handleSubmit: FormEventHandler = async (e: FormEvent) => {
    e.preventDefault();
    const formData: FormData = new FormData(e.target as HTMLFormElement);
    const formValues: { [k: string]: FormDataEntryValue } =
        Object.fromEntries(formData);

    const { username, email, password } = formValues;

    try {
        const res = await fetch("/api/register", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({ username, email, password }),
        });

        if (!(res.status === 201)) {
          setError(new DuplicateUserError());
        } else {
          // login user
        }

    } catch (err: any) {
        console.log(err);
    }
  };

  if (error) {
    return (
      <Error 
        error={error} 
        reset={() => setError(null)} 
      />);
  }

  return (
    <div className={styles.container}>
      <div className={styles.login}>
        <form className={styles.form} onSubmit={handleSubmit}>
          <Link href="/login" className={styles.register}>
            switch to login
          </Link>
          <input
            className={styles.input}
            placeholder="username"
            type="text"
            name="username"
            autoComplete="off"
            required
          />
          <input
            className={styles.input}
            placeholder="email"
            type="email"
            name="email"
            autoComplete="off"
            required
          />
          <input
            className={styles.input}
            placeholder="password"
            type="password"
            name="password"
            required
          />
          <button className={styles.button}>Register</button>
        </form>
      </div>
    </div>
  );
};

export default Register;


我想做的是当一个新用户在站点上注册时更新我的全局状态。具体来说,当注册成功完成时,我希望用户在站点上登录(通过身份验证)。有谁知道如何在这里完成Register组件中的代码?

aamkag61

aamkag611#

您可以通过调用login()函数来设置token,如下所示。

const Register: React.FC = (): JSX.Element => {
  const [error, setError] = useState<Error | null>(null);
  const login = useAuthStore(state => state.login);

  const handleSubmit: FormEventHandler = async (e: FormEvent) => {
    e.preventDefault();
    const formData: FormData = new FormData(e.target as HTMLFormElement);
    const formValues: { [k: string]: FormDataEntryValue } =
        Object.fromEntries(formData);

    const { username, email, password } = formValues;

    try {
        const res = await fetch("/api/register", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({ username, email, password }),
        });

        if (!(res.status === 201)) {
          setError(new DuplicateUserError());
        } else {
           login('token-here'); //set state
        }

    } catch (err: any) {
        console.log(err);
    }
  };
  //... existing code
};

export default Register;

字符集
tokenisAuthenticated现在是全局更新的,可以这样访问:

const isAuthenticated = useAuthStore((s) => s.isAuthenticated);

编辑

请记住,这只会设置令牌,而不会验证用户。您还需要验证令牌。
您可以通过在应用中添加useEffect来解决这个问题,并让它在每次刷新时从localstorage验证令牌。如果令牌有效,则调用login()函数并将用户设置为isAuthenticated
示例如下:
App.tsx:

export default function App() {
  useEffect(() => {
    useCurrentUser();
  }, []);
  return <></>;
}
export async function useCurrentUser() {
   const login = useAuthStore((state) => state.login);
   const data = await fetch('url'); //auth endpoint that validates the token
   if (data) {
      login('token-here');
   }
}

的字符串

相关问题