Reactの続きです。前回はステートで条件分岐やループをやってみました。今回は、コンポーネントの階層(ネスト)を超えて共通の値を渡すのに便利な「コンテクスト(Context)」という機能を体験したく。それではいきましょう!
【目次】
- コンテクスト(Context)とは
- コンテクストの書き方
- コンテクストでネストされたコンポーネントに値を渡す
- プロバイダ(Provider)とは
- プロバイダの書き方
- プロバイダ(Provider)でコンテクストの値を変更する
- 最後に
※参考:前回記事
https://www.i-ryo.com/entry/2020/06/02/201503
※参考:Reactを習得するためにやったことまとめ
qiita.com
コンテクスト(Context)とは
今回も掌田さんの「React.js & Next.js入門」を参考に進める。

- 作者:掌田津耶乃
- 発売日: 2019/08/30
- メディア: Kindle版
書籍ではコンポーネント編の次にRedux編に入るが、コンポーネント編の最後に「コンテクスト」という機能の解説があった。
React公式サイトではこちらにあたる
コンテクストは各階層で手動でプロパティを下に渡すことなく、コンポーネントツリー内でデータを渡す方法を提供します。
※参考:コンテクスト – React
コンテクストの書き方
コンポーネントの外でコンテクストを生成する。
const コンテクスト = React.createContext(値);
React.createContext
コンテクストオブジェクトを作成します。
※参考:コンテクスト – React
コンポーネント内でコンテクストを読み込む。
static contextType = コンテクスト;
Class.contextType
クラスの contextType プロパティには React.createContext() により作成されたコンテクストオブジェクトを指定することができます。これにより、this.context を使って、そのコンテクストタイプの最も近い現在値を利用できます。
※参考:コンテクスト – React
そうするとJSXのタグの中でコンテクストの値を呼び出せる
<hoge>{this.context.値}</hoge>
コンポーネントのネストが深いと値を「親→子→孫→ひ孫…」と「バケツリレー」で渡す必要がある。コンテクストを使うと「ひ孫」にも値を直接渡すことができる。
コンテクストでネストされたコンポーネントに値を渡す
実際にやってみた。
App.js変更内容
まず、変数data
にオブジェクト(連想配列)でデータを用意
let data = { title: 'はじめてのこんてきすと', message: 'これはコンテキストを使って読み込んでみたテキストなんです。はい。' }
変数data
はコンポーネントの外にある。
変数HajimeteContext
でcreateContext()
でdata
を読み込む。これもコンポーネントの外。
const HajimeteContext = React.createContext(data);
「App」コンポーネントの中で「Title」「Message」コンポーネントがネストしてる
class App extends React.Component { render() { return ( <div className="App"> <header className="App-header"> <div className="App-images"> <Img align="left" /> <Img align="center" /> <Img align="rignt" /> </div> <h1>コンテキストテスト</h1> <Title /> <Message /> </header> </div> ); } }
「Title」コンポーネントでHajimeteContext
コンテクストを読み込みtitle
の値を表示
class Title extends React.Component { static contextType = HajimeteContext; render() { return ( <div> <h2>{ this.context.title }</h2> </div> ); } }
「Message」コンポーネントでHajimeteContext
コンテクストを読み込みmessage
の値を表示
class Message extends React.Component { static contextType = HajimeteContext; render() { return ( <div> <p>{ this.context.message }</p> </div> ); } }
挙動確認
Reactを起動!
npm start
ブラウザが立ち上がる。
おお!コンテクストの値がコンポーネントに表示されとる!
App.jsコード全体
import React, { Component } from 'react'; import Img from './Img'; import './App.css'; let data = { title: 'はじめてのこんてきすと', message: 'これはコンテキストを使って読み込んでみたテキストなんです。はい。' } const HajimeteContext = React.createContext(data); class App extends React.Component { render() { return ( <div className="App"> <header className="App-header"> <div className="App-images"> <Img align="left" /> <Img align="center" /> <Img align="rignt" /> </div> <h1>コンテキストテスト</h1> <Title /> <Message /> </header> </div> ); } } class Title extends React.Component { static contextType = HajimeteContext; render() { return ( <div> <h2>{ this.context.title }</h2> </div> ); } } class Message extends React.Component { static contextType = HajimeteContext; render() { return ( <div> <p>{ this.context.message }</p> </div> ); } } export default App;
プロバイダ(Provider)とは
先ほどのコンテクストは値を読み込むのみだったが、コンテクストの構造は保ったままま値だけを変えたい時がある。そういうときにはプロバイダ(Provider)という機能を使う。
全てのコンテクストオブジェクトにはプロバイダ (Provider) コンポーネントが付属しており、これによりコンシューマコンポーネントはコンテクストの変更を購読できます。
※参考:コンテクスト – React
プロバイダの書き方
コンポーネントをコンテキスト.Provider
タグで囲う。
<コンテキスト.Provider value="値"> // コンポーネント </ コンテキスト.Provider>
囲われた中のコンポーネントの値だけが変更される。
プロバイダ(Provider)でコンテクストの値を変更する
実際にやってみる。
App.js変更内容
「App」コンポーネントにプロバイダーの値newdata
を設定
class App extends React.Component { newdata = { title: 'はじめてのぷろばいだ', message: 'ここだけプロバイダを使って書き換えてみたテキストなんです。はい。' } // 中略 }
「Title」「Message」コンポーネントを3つずつ読み込んでいるが2つ目のみHajimeteContext.Provider
で囲いnewdata
の値を読み込む。
class App extends React.Component { // 中略 render() { return ( <div className="App"> <header className="App-header"> // 中略 <Title /> <Message /> <HajimeteContext.Provider value={this.newdata}> <Title /> <Message /> </HajimeteContext.Provider> <Title /> <Message /> </header> </div> ); } }
挙動確認
ブラウザを確認すると…
やた!2番目だけプロバイダの値になっている!
App.jsコード全体
import React, { Component } from 'react'; import Img from './Img'; import './App.css'; let data = { title: 'はじめてのこんてきすと', message: 'これはコンテキストを使って読み込んでみたテキストなんです。はい。' } const HajimeteContext = React.createContext(data); class App extends React.Component { newdata = { title: 'はじめてのぷろばいだ', message: 'ここだけプロバイダを使って書き換えてみたテキストなんです。はい。' } render() { return ( <div className="App"> <header className="App-header"> <div className="App-images"> <Img align="left" /> <Img align="center" /> <Img align="rignt" /> </div> <h1>コンテキストテスト</h1> <Title /> <Message /> <HajimeteContext.Provider value={this.newdata}> <Title /> <Message /> </HajimeteContext.Provider> <Title /> <Message /> </header> </div> ); } } class Title extends React.Component { static contextType = HajimeteContext; render() { return ( <div> <h2>{ this.context.title }</h2> </div> ); } } class Message extends React.Component { static contextType = HajimeteContext; render() { return ( <div> <p>{ this.context.message }</p> </div> ); } } export default App;
最後に
ということでコンテクストからの値の読み込みをやってみました。自分はまだReactで大規模な物を作っていないため、コンポーネント間の「バケツリレー」の辛さはあまり感じていないんですが、値と直接関係ないコンポーネントが汚染されないのはいい感じですね。
次回からは「Redux」による値の状態管理を体験してみたく思います。それではまた!
※参考:Reactを習得するためにやったことまとめ
qiita.com