0
2

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 3 years have passed since last update.

React Contextを使う

Posted at

概要

あるコンポーネントから、子、孫のコンポーネントに値を渡すのに
通常だとpropsを使って順番に橋渡ししていくので手間ですが、
Contextを使うことでそんな面倒はなしにグローバルに値にアクセスできます。
アプリ全体で使う設定をもたせるのに便利だと思います。
Reduxが嫌いな人におすすめです。

下記サンプルではParentView -> MiddleView -> ChildViewの階層になっています。

Contextを作成する

const SettingContext = React.createContext({ xxx, yyy });

コンポーネントの外に定義しておきます。
引数はデフォルト値になります。
親をたどってProviderがなかった場合に適用されるようです。(そんな事あるのか?)

値をセットする

        <SettingContext.Provider value={ xxxx }>
          <MiddleView setting={this.state} />
        </SettingContext.Provider>

作成したContextのProviderをタグに使ってvalueに値を入れます。

値をゲットする

やり方は2通りあるようです。

  • contextTypeを設定する
    クラスのcontextTypeプロパティにコンテキストを設定します。
    そしてthis.contextで値を取り出します。
class ChildView1 extends React.Component {
  render() {
    return (
      <div>
        <h3>Passed by contextType</h3>
        <p>{this.context.color}</p>
        <p>{this.context.size}</p>
      </div>
    );
  }
}
ChildView1.contextType = SettingContext;
  • Consumerを使う
    作成したContextのConsumerをタグに使います。
    中で関数の引数に値が入るのでそれを使います。
class ChildView2 extends React.Component {
  render() {
    return (
      <div>
        <SettingContext.Consumer>
          {context => {
            return (
              <React.Fragment>
                <h3>Passed by Consumer</h3>
                <p>{context.color}</p>
                <p>{context.size}</p>
              </React.Fragment>
            );
          }}
        </SettingContext.Consumer>
      </div>
    );
  }
}

子のコンポーネントから値を更新する

メソッドを作成してProviderに渡して値と同じように使います。

  this.updateState = () => {
      console.log('update');
      this.setState({
        color: this.state.color + '!',
        size: this.state.size + 1
      });
    };

サンプルコード

import React from 'react';

// Contextを定義
const SettingContext = React.createContext({
  // default values
  color: 'red',
  size: 40,
  updateState: () => {},
  resetState: () => {}
});

// Context使わない場合
class ChildView extends React.Component {
  render() {
    return (
      <div>
        <h3>Passed by props</h3>
        <p>{this.props.setting.color}</p>
        <p>{this.props.setting.size}</p>
      </div>
    );
  }
}

// contextTypeを追加
class ChildView1 extends React.Component {
  render() {
    return (
      <div>
        <h3>Passed by contextType</h3>
        <p>{this.context.color}</p>
        <p>{this.context.size}</p>
        <button onClick={this.context.updateState}>update</button>
      </div>
    );
  }
}
ChildView1.contextType = SettingContext;

// Consumerを追加
class ChildView2 extends React.Component {
  render() {
    return (
      <div>
        <SettingContext.Consumer>
          {context => {
            return (
              <React.Fragment>
                <h3>Passed by Consumer</h3>
                <p>{context.color}</p>
                <p>{context.size}</p>
                <button onClick={context.updateState}>update</button>
              </React.Fragment>
            );
          }}
        </SettingContext.Consumer>
      </div>
    );
  }
}

class MiddleView extends React.Component {
  render() {
    return (
      <div>
        <h2>Parent</h2>
        <ChildView setting={this.props.setting} />
        <ChildView1 />
        <ChildView2 />
      </div>
    );
  }
}

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

    this.updateState = () => {
      console.log('update');
      this.setState({
        color: this.state.color + '!',
        size: this.state.size + 1
      });
    };

    this.state = {
      color: 'green',
      size: 50,
      updateState: this.updateState
    };
  }

  render() {
    return (
      <div className="App">
        <SettingContext.Provider value={this.state}>
          <MiddleView setting={this.state} />
        </SettingContext.Provider>
        <div>
          <h2>default</h2>
          <ChildView1 />
          <ChildView2 />
        </div>
      </div>
    );
  }
}

export default ParentView;

まとめ

contextTypeの方がスッキリして見えるがクラス外にコードを書くのが嫌。
単純なものならReduxを使うよりシンプルというのは言えるかな。
初心者の私にはわかりませんが。

0
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?