ログイン情報をContextで、どのコンポーネントからでも取得する方法

# 注意
あらかじめ言っておきますが、筆者は初心者なので、自分なりの解釈でまとめています。「100%信じるぜ！」という気持ちで読まないようお願いします。どうぞよろしく！

# 参考
https://ja.react.dev/learn/passing-data-deeply-with-context

https://youtu.be/zEGvDDX-8i0?si=NyOccVM2aNvJ8D7l

# 経緯
ポートフォリオ用のアプリを作成しているのですが、ログイン情報をどのコンポーネントからも取得したかったので、その際にcontextを使用したので、備忘録として残しておくことにしました。

私が作成したアプリは、layout.tsxでログイン情報を取得し、`<Header user_data={user_data}></Header> `これで、Headerにpropsとして渡しておりました。
しかし、深いコンポーネントでもログイン情報を取得する必要があったので、propsで渡すと、コードが冗長になるよなぁと考えました。そこで、`context`を使用するとpropsで渡す必要がないということがわかったので、今回使用することとしました。

# 使用技術
・typescript
・nextjs
・supabase

# 今回のコード

```typescript:layout.tsx
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
    //今回supabaseより、user情報を取得しました。
    const supabase = await createClient()
    const { data, error } = await supabase.auth.getUser()
    const user_metadata = data.user?.user_metadata as UserMetadata
    const user_data : {email:string|null} = {
        email:user_metadata?.email
    }

  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased flex w-screen`}>
          <Sidebar></Sidebar>
          <div className="grow bg-white m-2 rounded-2xl h-screen flex flex-col">
            <Header user_data={user_data}></Header> 
            {children}
          </div>
      </body>
    </html>
  );
}
```

`layout`配下に以下の`RecipeCreation.tsx`があります。
```typescript:RecipeCreation.tsx
const RecipeCreation = () => {

return(
    <div>
        ここにユーザー情報を表示したい
    </div>
)}
```

# 用語の意味
## コンテクスト
今回説明する内容です
>引用:React公式リファレンスより
>コンテクスト：props 受け渡しの代替手段 。propsのバケツリレーを防ぐ。

## プロバイダー
コンテクストの値を**提供**するもの
プロバイダーで囲まれたコンポーネントのコンテクストを使用することができます

# 使用方法
## 1.コンテクストを作成する（箱を作成する）

```typescript:UserContext

type UserContextType = {
    email:string
} | null

export const UserContext = createContext<UserContextType>(null);
```

## 2.プロバイダーを作成する
```typescript:UserContext.tsx
export const UserProvider = ({ children }: { children: React.ReactNode }) => {
    const [userEmail, setUserEmail] = useState<UserContextType>(null)
    //ユーザー情報を取得する
    useEffect(() => {
          const fetchUser = async () => {
            const supabase = createClient()
            const { data } = await supabase.auth.getUser()
            const email = data.user?.user_metadata?.email ?? null
            setUserEmail({ email })
          }
          fetchUser()
    }, [])

    return (
        <UserContext.Provider value={userEmail}>
            {children}
        </UserContext.Provider>
    )
}
```
以下を返すことにより、「`UserContext`の値は`userEmail`ですよ」というプロバイダとなります
```typescript
<UserContext.Provider value={userEmail}>
    {children}
</UserContext.Provider>
 ```

:::note
`children`とすることで、`UserProvider`で囲まれた、コンポーネントが`UserContext`を呼び出すことにより、ユーザー情報を取得することができます、
:::


## 3.プロバイダでアプリ全体を囲む
```typescript:layout.tsx
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased flex w-screen`}>
        <UserProvider>
          <Sidebar></Sidebar>
          <div className="grow bg-white m-2 rounded-2xl h-screen flex flex-col">
            <Header></Header>
            {children}
          </div>
        </UserProvider>
      </body>
    </html>
  );

```

## 4.`useContext`でコンテクストを使用する 
Contextを受け取りたいコンポーネントで`useContext`を使用することでContextを呼び出せます。
```typescript:RecipeCreation.tsx
import { UserContext } from '@/context/UserContext'

const RecipeCreation = () => {
  const userEmail = useContext(UserContext)

  return (
    <div>
      ここにユーザー情報を表示したい
    </div>
  )
}
```

## 5.ログイン情報を表示する。
```typescript:RecipeCreation.tsx
const RecipeCreation = () => {
return(
    <div>
        //ここにユーザー情報を表示したい
        {userEmail?.email}
    </div>
)}
```

# 感想
すこし複雑でわかりにくい気がしますが、じっくり考えれば、使えます！
Reduxを使用するより簡単なので、いいですね。
ガンガン開発していこう！