在Next/react裡,元件間的資料主要是靠props來傳遞,然而,當元件越來越多的時候,這樣的傳遞就會過於複雜,這時候就可以利用context來分享資料。在Material-UI裡,會使用ThemeProvider,ThemeProvider就是利用context。當然,也可以使用更複雜的Redux/Recoil來達成這樣的效果,不過,多數的情況下,Context就能解決問題了。在Context裡,有三個基本概念:首先,透過createContext產生一個context,接下來,利用context.Provider指定使用的範圍,透過useContext取得context。

createContext

先利用createContext,產生一個context

/components/context/UserContext.jsx

export const UserContext = React.createContext({
  username: "testing",
});

context.Provider

如果希望整個專案都可以取得context內容,在Next.js裡,就是修改_App.tsx/_App.js,在<Component />之外,加上<UserContext.Provider>,就會讓全部的元件都可以取得UserContext的內容。

import '../styles/globals.css'
import type { AppProps } from 'next/app'

**import { UserContext } from '@/components/context/UserContext';**

function MyApp({ Component, pageProps }: AppProps) {
  return (
    **<UserContext.Provider value={{ username: "test" }}>**
      <Component {...pageProps} />
    **</UserContext.Provider>**
  )

}

export default MyApp

useContext

想取得內容時,可利用useContext取得內容,注意,內容會是”Hello, test”,而不是”Hello, testing”,因為我們透過Provider改寫了值。

import { useContext } from 'react';
import { UserContext } from '@/components/context/UserContext';
export default function Home() {
  const user = useContext(UserContext);

  return (
    <div>Hello, {user.username}</div>
  )
}

將context應用於firebase authentication

我們先修改一下

/components/context/UserContext.jsx

import React, { useState, useEffect } from "react";
import { getApps, initializeApp } from "firebase/app";
import { getAuth, onAuthStateChanged } from "firebase/auth";
import { firebaseConfig } from "@/settings/firebaseConfig";

export const UserContext = React.createContext();

export function UserProvider({ children }) {
  const user = useFirebaseAuth();
  return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
}

export default function useFirebaseAuth() {
  const [currentUser, setCurrentUser] = useState(null);
  if (getApps().length === 0) {
    initializeApp(firebaseConfig);
  }
  const auth = getAuth();
  useEffect(() => {
    const unsub = onAuthStateChanged(auth, (user) => {
      if (!user) {
        setCurrentUser(null);
        return;
      }
      setCurrentUser(user);
      console.log(user);
    });

    return () => {
      unsub();
    };
  }, [auth]);
  return currentUser;
}

因為我們在UserContext裡寫了一個UserProvider,所以,_App.tsx就可以改成:

import '../styles/globals.css'
import type { AppProps } from 'next/app'

**import { UserContext } from '@/components/context/UserContext';**

function MyApp({ Component, pageProps }: AppProps) {
  return (
    **<UserProvider>**
      <Component {...pageProps} />
    **</UserProvider>**
  )

}

export default MyApp

使用時就可以直接取得利用getAuth()所取得的資料,例如:

import { useContext } from 'react';
import { UserContext } from '@/components/context/UserContext';
export default function Home() {
  const user = useContext(UserContext);
  console.log('user', user)

  return (
    <div>Hello, {user && user.displayName}</div>
  )
}