Context

コンテキスト

Context を分かりやすく?

「Context」と聞くとちょっと難しそうに感じますよね。でも安心してください、一緒に見ていきましょう。

ContextはReact(Next.jsもReactベースなので含まれます)の機能の一つで、コンポーネントツリー全体にデータを提供するためのものです。つまり、Contextを使用すると、コンポーネントツリーのどこからでもアクセスできる共有データを作ることができます。通常、データはpropsとして子コンポーネントに渡されますが、Contextを使用すると、いくつかのレベルをスキップしてデータを渡すことができます。

それでは、例え話を使ってContextをもっと具体的に理解してみましょう。

Contextを「空気」と思い浮かべてみてください。空気は周囲に存在し、我々が息をすることで酸素を取り入れます。同様に、Contextもアプリケーションの「空気」のようなものです。それはアプリケーション全体で存在し、各コンポーネントはContextから必要なデータを「呼吸」することができます。

具体的には、ユーザー情報やテーマ設定など、アプリケーション全体で共有するデータをContextとして設定できます。すると、これらの情報を必要とするすべてのコンポーネントは、直接Contextからデータを取得できます。このとき、祖先コンポーネントから一連のpropsを経由してデータを受け取る必要はありません。すごく便利ですよね?

TypeScriptと組み合わせると、Contextのデータの型を明確にして、より堅牢なコードを書くことができます。一体ナンノコッチャ?って最初は思ったかもしれませんが、これで少しは理解が深まったでしょうか。ここまで大丈夫ですか?

つまり、Context は React の機能の 1 つで、アプリケーション内でデータを共有することができます。データを一箇所に集め、必要なコンポーネントから取得できるようにすることができます。例えば、ログインユーザー情報やテーマ、多言語対応など、アプリケーション内で共通して使用されるデータをコンポーネント間で簡単に受け渡すことができるというわけです。

Context の使い方

Context を使うには、まずReact.createContext()を使って Context オブジェクトを作成します。この Context オブジェクトには、共有するデータを格納します。次に、コンポーネントに Context を提供するために、<Context.Provider>を使用します。この Provider コンポーネントは、valueというプロパティを持ち、その値が全ての子コンポーネントで共有されます。

// コンテキストの作成
const UserContext = React.createContext({ name: '' })

// ユーザー情報を表示するコンポーネント
const UserInfo = () => {
  const { name } = useContext(UserContext)
  return <p>{`Welcome, ${name}!`}</p>
}

// ユーザー情報を提供する親コンポーネント
const App = () => {
  const user = { name: 'John' }
  return (
    <UserContext.Provider value={user}>
      <UserInfo />
    </UserContext.Provider>
  )
}

この例では、UserContextという Context オブジェクトを作成し、AppコンポーネントでUserContext.Providerを使用して、子コンポーネントのUserInfouserを渡しています。そして、UserInfoコンポーネントでは、useContextフックを使って、UserContextを参照しています。useContextフックを使用すると、コンテキストオブジェクトから値を取得できます。

Context の利点

また、createContextを使用すると、ProviderConsumerという 2 つのコンポーネントが自動的に生成されます。Providerは、コンテキストを提供するコンポーネントであり、Consumerは、コンテキストを受け取るコンポーネントです。以下は、createContextを使用してコンテキストを作成し、それを使用してProviderConsumerを作成する例です。

import React, { createContext, useContext, useState } from 'react'

// コンテキストを作成
type User = {
  name: string
  age: number
}

type UserContextType = {
  user: User
  setUser: React.Dispatch<React.SetStateAction<User>>
}

const UserContext = createContext<UserContextType | null>(null)

// Providerを作成
const UserProvider = ({ children }) => {
  const [user, setUser] = useState<User>({ name: '', age: 0 })

  return <UserContext.Provider value={{ user, setUser }}>{children}</UserContext.Provider>
}

// Consumerを作成
const UserProfile = () => {
  const { user } = useContext(UserContext)

  return (
    <div>
      <p>Name: {user.name}</p>
      <p>Age: {user.age}</p>
    </div>
  )
}

// 使用例
const App = () => {
  return (
    <UserProvider>
      <UserProfile />
    </UserProvider>
  )
}

この例では、createContextを使用してUserContextという名前のコンテキストを作成し、その型を定義しています。次に、UserProviderという名前のコンポーネントを作成しています。このコンポーネントは、状態としてUserを持ち、UserContextを提供する役割を持ちます。最後に、UserProfileという名前のコンポーネントを作成し、UserContextを受け取り、User情報を表示するコンポーネントとして機能します。

UserProviderコンポーネントでUserContext.Providerを使用して、UserContextを提供しています。UserProfileコンポーネントでは、useContextを使用して、UserContextからuserを受け取り、表示しています。

以上が、React のコンテキストの基本的な使い方になります。コンテキストを使用することで、親コンポーネントから子コンポーネントにデータを渡すことができ、コンポーネントの再利用性を高めることができます。