😄
React Hooksの10種類を理解する(Basic: useContext)
React Hooksの10種類を理解する(Basic: useContext)
contextの復習
contextとは
- contextは、各階層で手動でプロパティを子にわたすことなく、component tree内でデータを渡す方法を提供するものある。
React.createContext
const newContext = React.createContext(defaultValue);
-
context objectを作成する。Reactがこのcontext objectが登録されているcomponentをrenderする際には、tree内の最も近い上位の一致する
Provider
から現在のcontextを読み取る。 -
defaultValue
引数は、componentがtree内の上位に対応するProviderを持っていないときのみに使用される。
Context.Provider
<NewContext.Provider value={...}>
- このprovider componentは、
value
プロパティを受け取り、子要素にあるconsumer componentと接続することができる。 - providerはnestして(まとめて)tree内のより深い位置で値を上書きすることができる。
- providerの子孫のすべてのconsumerは、providerの
value
プロパティが変更されるたびに再renderされる。
Class.contextType
- hooksにはあまり関係ないため省略
Context.Consumer
<MyContext.Consumer>
{value => ...}
</MyContext.Consumer>
- contextの変更を購読するreact componentである。
- function as a childが必要となってくる。
- 引数
value
は、tree内の上位で一番近いcontext用のproviderのvalue
プロパティと等しくなる。 - 上位に存在しない場合、引数の
value
はcreateContext()
から渡されたdefaultValue
と等しくなる。
contextに関する注意事項
- contextは参照の同一性を使用していつ再renderするかを決定するため、providerの親が再renderするときにconsumerで意図しないrenderを引き起こす可能性がある。そのため、親のstateにvalueをリフトアップすることがある。
before
class App extends React.Component {
render() {
return (
<MyContext.Provider value={{something: 'something' /* ここが問題 */}}>
<Toolbar />
</MyContext.Provider>
);
}
}
after
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'}, // このstateに予めvalueを設置
};
}
render() {
return (
<MyContext.Provider value={this.state.value}>
<Toolbar />
</MyContext.Provider>
);
}
}
useContext
の基本
const value = useContext(MyContext);
-
React.createContext
からの戻り値を受け取り、そのcontextの現在地を返す。 -
MyContext.Provider
のvalueの値によってcontextの現在地が決定される。 -
MyContext.Provider
が更新された場合、このhookはMyContext
providerに渡された最新のvalue
を使って再renderを発生させる。 -
useContext
にわたす引数はcontext objectそれ自体。 -
<MyContext.Consumer>
と役割は同等。 -
useContext(MyContext)
は現在のcontextの値を読み取り、その変化を購読することしかできない。よって、<MyContext.Provider
が必要となってくる。
例示(公式より抜粋)
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
Discussion