概要
あるコンポーネントから、子、孫のコンポーネントに値を渡すのに
通常だと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を使うよりシンプルというのは言えるかな。
初心者の私にはわかりませんが。