React 16.3では、まったく新しいコンテキストAPIにアクセスできるようになりました。 Reactの古いコンテキストAPIでは、開発者はそれを使用しないように公式に推奨されていましたが、新しいコンテキストAPIは一級市民になりました。

ReduxやMobXのような状態管理ライブラリの代わりとなるものではありませんが、コンテキストAPIを使用すると、小道具として渡すことなく、複数のコンポーネント間でグローバルデータを簡単に共有できます。 これは、 prop-drilling 問題として知られる一般的な問題を解決します。この問題では、小道具を必要とするコンポーネントに到達するために、ツリー内の複数のコンポーネントに小道具を渡す必要があります。

新しいAPIは、ツリー内のコンポーネントの大部分が必要とするデータを提供するのに特に役立ちます。 選択したテーマや選択したロケールオプションなどのグローバル設定は、2つの良い例です。

この投稿では、新しいコンテキストAPIの使用方法をできるだけ短い単語で説明します。 アプリ内のコンポーネントに英語とフランス語の間の言語設定を提供する単純なLocaleコンテキストを作成します。 これは、アプリのグローバル設定を示すための簡単な例として意図されているだけであり、Reactの実際のi18nには、i18nextのようなより堅牢なソリューションがより適切であることに注意してください。

React.createContext

新しいコンテキストを作成するには、Reactの新しいcreateContext関数を使用します。

export const LocaleContext = React.createContext('en');

ここでは、デフォルト値‘en’ もコンテキストに渡しますが、必要に応じてこのデフォルト値を省略することもできます。

createContext関数は、ProviderおよびConsumerコンポーネントを返します。

プロバイダー

Provider コンポーネントは、コンテキストから値にアクセスする必要があるツリー内のコンポーネントをラップするために使用されます。 ここでは、 LocaleContext のプロバイダーをラップし、コンテキストのlocale値を変更する方法を提供するLocaleProviderコンポーネントを作成しましょう。

context / LocaleContext.js
import React from 'react';

export const LocaleContext = React.createContext();

class LocaleProvider extends React.Component {
  constructor(props) {
    super(props);

    this.changeLocale = () => {
      this.setState(state => {
        const newLocale = state.locale === 'en' ? 'fr' : 'en';
        return {
          locale: newLocale
        };
      });
    };

    this.state = {
      locale: 'en',
      changeLocale: this.changeLocale
    };
  }

  render() {
    return (
      <LocaleContext.Provider value={this.state}>
        {this.props.children}
      </LocaleContext.Provider>
    );
  }
}

export default LocaleProvider;

LocaleProvider コンポーネントが、コンテキストのProviderコンポーネントの単なる薄いラッパーであることに注意してください。 コンテキストの値は、 value プロップを使用してプロバイダーに渡され、LocaleContextの子をレンダリングするだけです。

コンポーネントの状態をコンテキスト値として渡し、そこからロケール値と値を変更するためのchangeLocaleメソッドを使用できるようになります。

プロバイダーの使用

Appコンポーネントのトップレベルでプロバイダーを利用できます。

App.js
import React, { Component } from 'react';

import LocaleProvider from './context/LocaleContext';
import Greeting from './Greeting';
import ToggleLocale from './ToggleLocale';

class App extends Component {
  render() {
    return (
      <LocaleProvider>
        <Greeting />
        <ToggleLocale />
      </LocaleProvider>
    );
  }
}

export default App;

消費者

あとは、Consumerコンポーネントを使用してコンテキストから値にアクセスするだけです。

Greetingコンポーネントは次のようになります。

Greeting.js
import React from 'react';

import { LocaleContext } from './context/LocaleContext';

export default () => {
  return (
    <LocaleContext.Consumer>
      {localeVal =>
        localeVal.locale === 'en' ? <h1>Welcome!</h1> : <h1>Bienvenue!</h1>
      }
    </LocaleContext.Consumer>
  );
};

また、ToggleLocaleコンポーネントは次のようになります。

ToggleLocale.js
import React from 'react';

import { LocaleContext } from './context/LocaleContext';

export default () => {
  return (
    <LocaleContext.Consumer>
      {localeVal => (
        <button onClick={localeVal.changeLocale}>Change language</button>
      )}
    </LocaleContext.Consumer>
  );
};

Consumer コンポーネントは、レンダリングプロップパターンを使用し、コンテキストから値を受け取る子プロップとしての関数を期待します。 次に、コンテキストの値にアクセスして、コンテキストが利用できるようにするメソッドを呼び出すことができます。

これにより、アプリのグリーティングメッセージをWelcomeBienvenueの間で切り替えることができます。


この例では、GreetingおよびToggleLocaleコンポーネントは、 LocaleProvider コンポーネントの直接の子ですが、コンポーネントツリーの任意の深さにある可能性があります。コンテキストのコンシューマーコンポーネントが使用され、プロバイダーがツリーの上位にある限り、グローバルコンテキストデータにアクセスできます。

⚛️これで、アプリで新しいコンテキストAPIの使用を開始できます。 詳細については、公式ドキュメントを参照することもできます。