useContextのしくみ

[Dave Ceddia氏](https://daveceddia.com/about/)による全5回におよぶReact Hooks入門記事の第5回を本人の許可を得て意訳しました。
誤りやより良い表現などがあればご指摘頂けると助かります。

原文： https://daveceddia.com/usecontext-hook/

---

[すべての新しいReact Hooks](https://daveceddia.com/intro-to-hooks/)の中で議論中のテーマがあります。ほとんど全てが、ファンクションコンポーネントをクラスコンポーネント同等にするために存在しています。

`useContext` フックは少し違っています。仕事をよりラクにしてくれるだけのものです。

ReactのContext APIを知らない方のために補足しておきますと、アプリケーション内深くまでデータを渡す方法、それも手動で複数階層にまたがってバケツリレーをせずに済む方法です。データを引き回すことさえできれば良いという時には、Reduxのようなツールの代替手段として機能します。[Contextについて学び、Reduxとの違いを知るにはこちら](https://daveceddia.com/context-api-vs-redux/)へどうぞ。

この記事では、 `useContext` がどのようにContextを扱いやすくするのかを見ていきます。

> メモ：Hooksは現在α版であり、プロダクション環境ではまだ使用できません。APIはさらに変更される可能性があるため、現時点ではプロダクションアプリの書き換えはオススメしません。[Open RFC](https://github.com/reactjs/rfcs/pull/68)にコメントし、[公式ドキュメント](https://reactjs.org/docs/hooks-intro.html)や[FAQ](https://reactjs.org/docs/hooks-faq.html)にも目を通してください。

## 従来の一般的な方法

典型的なContext APIの使用例はこのような感じです。

```react
import React from "react";
import ReactDOM from "react-dom";

// Contextを生成する
const NumberContext = React.createContext();
// 2つの値を持つオブジェクトを返す
// { Provider, Consumer }

function App() {
  // Providerを活用して値を全ての
  // 子要素と孫要素に利用可能にする
  return (
    <NumberContext.Provider value={42}>
      <div>
        <Display />
      </div>
    </NumberContext.Provider>
  );
}

function Display() {
  // Consumerを活用してcontextから取得した値を使う
  // このコンポーネントはpropsを取らないことに注意！
  return (
    <NumberContext.Consumer>
      {value => <div>The answer is {value}.</div>}
    </NumberContext.Consumer>
  );
}

ReactDOM.render(<App />, document.querySelector("#root"));
```

[Context APIについて詳しくはこちら](https://daveceddia.com/context-api-vs-redux/)で触れています。

## useContextを使ったモダンな方法

`Display` を `useContext` フックを使ってリファクタして、どのような感じになるか見てみましょう。

```react
// useContextをimportする（もしくはReact.useContextを使う）
import React, { useContext } from 'react';

// ...

function Display() {
  const value = useContext(NumberContext);
  return <div>The answer is {value}.</div>;
}
```

これだけです。 `useContext` を呼び、 `React.createContext` から取得できるcontextオブジェクトを渡すと、値が利用可能になります。見やすくなったでしょう？

注目すべき唯一のポイントは、contextオブジェクトを丸ごと `useContext` に渡さなければならないということです。consumerだけではダメです！もし忘れるとReactが警告してくれますが、忘れないでくださいね？

## ネストされたConsumer

コンポーネントが複数の親contextからデータを受け取りたいような場合はこうなります。

```react
function HeaderBar() {
  return (
    <CurrentUser.Consumer>
      {user =>
        <Notifications.Consumer>
          {notifications =>
            <header>
              Welcome back, {user.name}!
              You have {notifications.length} notifications.
            </header>
          }
      }
    </CurrentUser.Consumer>
  );
}
```

たった2つの値を受け取るのにひどいネストになってしまいます。 `useContext` を使って良い感じにしてみましょう。

```react
function HeaderBar() {
  const user = useContext(CurrentUser);
  const notifications = useContext(Notifications);

  return (
    <header>
      Welcome back, {user.name}!
      You have {notifications.length} notifications.
    </header>
  );
}
```

ずっと読みやすくなりましたね。

## 広がるHooksの世界

今週カバーした以外にも多くのHooksがあります。メモ作成のための `useMemo` のような素晴らしいものありますので、ぜひ[公式のHooks APIドキュメント](https://reactjs.org/docs/hooks-reference.html)で学んでみてください。公式ドキュメントも素晴らしいですが、[Hooks入門](https://reactjs.org/docs/hooks-intro.html)から始めることをおすすめします。

Hooksウィークに投稿した私の他の記事も再掲します。

- [React Hooks超入門](https://daveceddia.com/intro-to-hooks)
- [React Hooksがよくわかる4つの例](https://daveceddia.com/usestate-hook-examples)
- [useReducerフック活用法](https://daveceddia.com/usereducer-hook-examples)
- [useEffectフックのしくみ](https://daveceddia.com/useeffect-hook-examples)

毎週記事を投稿しています（ビデオもたまに）。もっと情報が必要であれば、[ボックスにメールアドレスを登録](https://daveceddia.com/newsletter/)してください。