初心者がコンテクストを読んで箇条書きしています。
実際のサイトの方がわかりやすいです。わからないことも同時にメモしています。
- コンテクストは各階層で手動でプロパティを下に渡すことなく、 コンポーネントツリー内でデータを渡す方法を提供する
コンテクストをいつ使用すべきか
- ネストレベルが違う多くのコンポーネントからアクセスできる必要がある時。
- 欠点:コンポーネントの再利用が難しくなる
コンテクストを使わない選択肢もある
- 多くの階層を経由することだけを避けたいのであれば、コンポーネントコンポジションを使う
- 最終的に Avatar コンポーネントだけがプロパティを必要とするならば、Avatar コンポーネント自身を渡すようにすると
- コンポーネントに対して 1 つの子までという制限はありません。複数の子を渡したり、子のために複数の別々の「スロット」を持つことさえできます。
- 使わない時の欠点:制御の反転はアプリケーション内で取り回す必要のあるプロパティの量を減らし、ルートコンポーネントにより多くの制御を与えることにより、多くのケースでコードを綺麗にすることができます。しかし、この方法は全てのケースで正しい選択とはなりません:ツリー内の上層に複雑性が移ることは、それら高い階層のコンポーネントをより複雑にして、低い階層のコンポーネントに必要以上の柔軟性を強制します。
コンテクストを使用する前に
API
React.createContext
[コンテクストオブジェクトを作成]
const MyContext = React.createContext(defaultValue);
- コンテクストオブジェクトを作成
- React がこのコンテクストオブジェクトが登録されているコンポーネントをレンダーする場合、ツリー内の最も近い上位の一致する Provider から現在のコンテクストの値を読み取る
- defaultValue 引数は、コンポーネントがツリー内の上位に一致するプロバイダを持っていない場合のみ使用される。これは、ラップしない単独でのコンポーネントのテストにて役に立ちます。補足: undefined をプロバイダの値として渡しても、コンシューマコンポーネントが defaultValue を使用することはありません。
??わからなかったこと
ツリー内の最も近い上位の一致する Provider
直近の親っていう意味だろうか??
ラップしない単独でのコンポーネントのテストにて役に立ちます。
全く意味がわからない。。
ラッパーとは?
- 一時的にラップするために生成されるオブジェクトのことを『ラッパーオブジェクト』という
ラッパーオブジェクト
- StringオブジェクトをnewすることでStringオブジェクトのインスタンスを作れます。
- プリミティブ型の値を包んだ(ラップした)オブジェクトと言えます。 そのため、このようなオブジェクトをプリミティブ型の値に対してのラッパーオブジェクトと呼びます。
- 注記: undefinedとnullに対応するラッパーオブジェクトはありません。
Context.Provider
[プロバイダ (Provider) によりコンシューマコンポーネントはコンテクストの変更を購読できる]
<MyContext.Provider value = {/*何らかの値*/}>
- プロバイダは value プロパティを受け取り、これが子孫であるコンシューマコンポーネントに渡され
- 1 つのプロバイダは多くのコンシューマと接続することが出来る
- プロバイダの子孫の全てのコンシューマは、プロバイダの value プロパティが変更されるたびに再レンダーされる
- プロバイダからその子孫コンシューマ(.contextType や useContext を含む)への伝播は shouldComponentUpdate メソッドの影響を受けないため、コンシューマは祖先のコンポーネントが更新をスキップしている場合でも更新る
Class.contextType
?わからなかったこと
MyContextの値を使用し、マウント時に副作用を実行します
ってどういう意味だろう?MyContextは
class MyClass extends React.Component{
componentDidMount(){
let value = this.context;
/* MyContextの値を使用し、マウント時に副作用を実行します */
}
componentDidUpdate(){
let value = this.context;
}
componentWillUnmount(){
let value = this.context;
}
}
- この API では、1 つのコンテクストだけ登録することができます。
Context.Consumer
- コンテクストの変更を購読する React コンポーネント。関数コンポーネント 内でコンテクストを購読することができる。
<MyContext.Consumer>
{value => /* コンテクストの値に基づいて何かをレンダーします */}
</MyContext.Consumer>
- function as a child が必要です。この関数は現在のコンテクストの値を受け取り、React ノードを返す。この関数に渡される引数 value は、ツリー内の上位で一番近いこのコンテクスト用のプロバイダの value プロパティと等しくなる。
- このコンテクスト用のプロバイダが上位に存在しない場合、引数の value は createContext() から渡された defaultValue と等しくなる。
わからなかったこと
<DataProvider render={data => (
<h1>Hello {data.target}</h1>
)}/>
Context.displayName
- コンテクストオブジェクトは displayName という文字列型のプロパティをもつ。 React DevTools はこの文字列を利用してコンテクストの表示のしかたを決定する
例
動的なコンテクスト
theme-context.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext(
themes.dark // デフォルトの値
);
themed-button.js
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context;
return (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;