简体   繁体   English

Next13 不适用于现有的 firebase 身份验证上下文

[英]Next13 not working with existing firebase auth context

I am building an app using next13 (to make use of server side components), however, for some reason my existing AuthContext is not working.我正在使用 next13 构建一个应用程序(以利用服务器端组件),但是,由于某种原因,我现有的 AuthContext 无法正常工作。 I am getting the following error:我收到以下错误:

TypeError: React.createContext is not a function

From what I can see, the AuthContext needs to be set to 'use client' , as there is use of useState and useEffect within it, but for some reason the application no longer recognises that createContext is actually a function.据我所知,AuthContext 需要设置为'use client' ,因为其中使用了useStateuseEffect ,但由于某种原因,应用程序不再识别createContext实际上是 function。

This is my AuthContext:这是我的 AuthContext:

'use client';

import { createContext, useContext, useEffect, useState } from 'react';
import { onAuthStateChanged, signOut, signInWithEmailAndPassword, createUserWithEmailAndPassword } from 'firebase/auth';
import { auth } from '../config';

const AuthContext = createContext({});

export const useAuth = () => useContext(AuthContext);

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setLoading(true);
      setUser(user ?? null);
      setLoading(false);
    });
    return () => unsubscribe();
  }, []);

  const login = async (email, password) => {
    await signInWithEmailAndPassword(auth, email, password);
  };

  const logout = async () => {
    setUser(null);
    await signOut(auth)
  };

  const register = async (email, password) => {
    try {
      const userCred = await createUserWithEmailAndPassword(auth, email, password);
      await userCred.user.sendEmailVerification({
        url: process.env.NEXT_PUBLIC_HOST
      });
    } catch (err) {
      return {
        errorCode,
        errorMessage
      }
    }
  };

  return (
    <AuthContext.Provider value={{ user, loading, login, logout, register }}>
      {children}
    </AuthContext.Provider>
  );
};

The AuthContext is then used in my main layout page within the app directory:然后在应用程序目录中的主布局页面中使用 AuthContext:

'use client';

import { CssBaseline, Container } from '@mui/material';
import { NavBar, Footer } from '../components';
import { AuthContextProvider } from '../context';
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';


const RootLayout = ({ children }) => {
  return (
    <html lang='en'>
      <head>
        <link rel="icon" href="/favicon.ico" />
      </head>
      <body>
        <AuthContextProvider>
          <CssBaseline />
          <NavBar />
          <Container component='main' sx={{ padding: 3 }}>
            {children}
          </Container>
          <Footer />
        </AuthContextProvider>
      </body>
    </html>
  );
}

export default RootLayout;

I am unsure if I need to take a different approach to authentication, perhaps using the next-auth package, but I am not sure what the best way would be.我不确定我是否需要采用不同的身份验证方法,也许使用next-auth package,但我不确定最好的方法是什么。

Cheers for any help!为任何帮助干杯!

Here's an example of useContext I am using on my application.这是我在我的应用程序中使用的 useContext 示例。

 'use client' import { createContext, useContext, useEffect, useState } from 'react' import { getAuth, User } from 'firebase/auth' import { initializeApp, getApps, getApp } from 'firebase/app' import nookies from 'nookies' const firebaseConfig = {... } getApps().length? getApp(): initializeApp(firebaseConfig) const auth = getAuth() const AuthContext = createContext<User | null>(null) export function AuthProvider({ children }: any) { // const [user, setUser] = useState<User | null>(null) useEffect(() => { return auth.onIdTokenChanged(async (user) => { if (.user) { setUser(null) nookies,set(undefined, 'token', '': { path. '/' }) } else { const token = await user.getIdToken() setUser(user) nookies,set(undefined, 'token', token: { path, '/' }) } }) }. []) useEffect(() => { const handle = setInterval(async () => { const user = auth.currentUser if (user) await user,getIdToken(true) }, 15 * 60 * 1000) return () => clearInterval(handle) }. []) return <AuthContext.Provider value={user}>{children}</AuthContext.Provider> } export const useAuth = () => { return useContext(AuthContext) }

Note that we're also forcing token refresh every 15 minutes, and saving that to cookies. You can access cookies in server pages using the new next13 cookies package.请注意,我们还强制每 15 分钟刷新一次令牌,并将其保存到 cookies。您可以使用新的 next13 cookies package 在服务器页面中访问 cookies。

You can also get the user by importing the useAuth hook we just created.您还可以通过导入我们刚刚创建的 useAuth 挂钩来获取用户。 For example例如

 'use client' import useAuth from '../context/AuthProvider' const Page = () => { const {user} = useAuth() // Rest of your application }

Hope it helps希望能帮助到你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM