0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React状態管理2】useContext

Posted at

概要

Reactの状態管理の1つである、useContextについて学んだことをメモします。

学習内容

useContextとは

useContextとは、Reactで提供されているコンポーネントツリー内でのデータ共有機能。
propsによるバケツリレーを行うことなく、コンポーネント間でデータを共有できる。

利用手順

  1. Context領域の生成
    createContext()により、Context領域を生成する。通常、最上位のページ又はコンポーネントで用いる(_app.tsx等)。
export const TodoContext = createContext(TODOS);
  1. Context領域の利用範囲の設定
    生成したContext領域により、子ページまたは子コンポーネントをラップする(ラップされたコンポーネント内で、Context領域のデータが使える)。
    ラップする際には、Context領域のProviderコンポーネントを呼び出す。
    Context領域に設定するデータの値は、Providerコンポーネントの引数valueに保存する
return (
  <TodoContext.Provider value={todos}>
    <Component {...pageProps} todos={todos} setTodos={setTodos} />
  </TodoContext.Provider>
);
  1. Context領域のデータの利用
    Context領域に保存したデータを使用したいページやコンポーネントで、useContext()を呼び出す
const todos = useContext(TodoContext);
return (
    <h2>TODO: {todos.length}</h2>
)

使用例

  1. 変数todosを、Context領域TodoContextに保存
  2. Context領域の値todosを、propsを用いることなく別コンポーネントTodoCounter.tsxで利用
_app.tsx
import { createContext, useState } from "react";

const TODOS: Todo[] = [
  { id: 1, text: "foo", isDone: false },
  { id: 2, text: "bar", isDone: true },
];

export const TodoContext = createContext(TODOS); // Context領域の生成

export default function MyApp({ Component, pageProps }: AppProps) {
  const [todos, setTodos] = useState(TODOS);
  
  return (
    <TodoContext.Provider value={todos}>            {/*Context領域による子コンポーネントのラップ*/}
      <Component {...pageProps} todos={todos} setTodos={setTodos} />
    </TodoContext.Provider>                         {/*Context領域による子コンポーネントのラップ*/}
  );
}
TodoCounter.tsx
import { FC, useContext } from "react";
import { TodoContext } from "src/pages/_app";

export const TodoCounter: FC = () => {
    const todos = useContext(TodoContext); // propsを用いずにContext領域からTodoContext内の値todosを取得
    return (
        <h2>TODO: {todos.length}</h2>
    )
}

useContextを複数使う

useContextは同一ページ内で複数使うことができる。

_app.tsx
export const ThemeContext = createContext("light");
export const LangContext = createContext("ja");

export default function MyApp({ Component, pageProps }: AppProps) {
  const [todos, setTodos] = useState<Todo[]>(TODOS);
  const [theme, setTheme] = useState("light");
  const [lang, setLang] = useState("ja");

  return (
    <ThemeContext.Provider value={theme}>
      <LangContext.Provider value={lang}>
        <Layout todoCount={todos.length}>
          <button 
            onClick={() => {
              setTheme((prev) => prev === "dark" ? "light" : "dark");
              setLang((prev) => prev === "ja" ? "en" : "ja");
            }}
          >
            テーマ切り替え
          </button>
          <Component {...pageProps} todos={todos} setTodos={setTodos} />
        </Layout>
      </LangContext.Provider>
    </ThemeContext.Provider>
  );
}

useContextの問題点

useContextにはいくつか問題点があるため、外部パッケージ(Redux, Recoilなど)の状態管理を使うことが多い

  • 記述量が多い
  • useCallback()など、Reactの関数を使う必要がある
  • 複数の状態を持たせると状態同士の連携が困難
  • SSRとの相性があまりよくない

参考

IT Kingdom
GitHubリポジトリ
Context

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?