context
定義: Context提供了一種方式,能夠讓資料在元件樹中傳遞,而不必一級一級手動傳遞。
API : createContext(defaultValue?)。
使用方法:
首先要引入createContext
import React, { Component, createContext } from 'react';
然後建立一個Context
const BatteryContext = createContext();
然後用BatteryContext.Provider包裹元件並且傳遞屬性值。
<BatteryContext.Provider value={60}>
<Middle /> //子元件
</BatteryContext.Provider>
為了方便看出效果,將定義一個子元件和一個孫元件。然後不通過子元件,孫元件直接取值。
import React, { Component, createContext } from 'react';
const BatteryContext = createContext();
//宣告一個孫元件
class Leaf extends Component {
render() {
return (
)
}
}
//宣告一個子元件
class Middle extends Component {
render() {
return <Leaf />
}
}
class App extends Component {
render(){
return (
<BatteryContext.Provider value={60}>
<Middle />
</BatteryContext.Provider>
);
}
}
export default App;
孫元件需要BatteryContext.Consumer來接收值,Consumer裡面不能直接渲染其他元件,而是要宣告一個函式。函式的引數就是context的值。
class Leaf extends Component {
render() {
return (
<BatteryContext.Consumer>
{
battery => <h1>Battery : {battery}</h1>
}
</BatteryContext.Consumer>
)
}
}
效果圖;
這樣沒通過Middle元件來傳遞值,但是Leaf元件能通過context來獲得屬性。這就是context的基本用法。
context不但能跨層級來傳遞屬性值,還能在屬性值發生變化的時候重渲染Consumer下面的元素,舉個例子:
在state中定義battery並賦值
state = {
battery: 60
}
然後做一個按鈕,每次點選的時候都要battery減一。 程式碼:
render() {
const { battery } = this.state;
return (
<BatteryContext.Provider value={battery}>
<button
type="button"
onClick={() => this.setState({ battery: battery - 1 })}
>
減減
</button>
<Middle />
</BatteryContext.Provider>
);
}
全部程式碼:
import React, { Component, createContext } from 'react';
const BatteryContext = createContext();
//宣告一個孫元件
class Leaf extends Component {
render() {
return (
<BatteryContext.Consumer>
{
battery => <h1>Battery : {battery}</h1>
}
</BatteryContext.Consumer>
)
}
}
//宣告一個子元件
class Middle extends Component {
render() {
return <Leaf />
}
}
class App extends Component {
state = {
battery: 60
}
render() {
const { battery } = this.state;
return (
<BatteryContext.Provider value={battery}>
<button
type="button"
onClick={() => this.setState({ battery: battery - 1 })}
>
減減
</button>
<Middle />
</BatteryContext.Provider>
);
}
}
export default App;
效果圖:
這樣每次點選都會使battery得數值發生變化,從而重渲染Consumer下面的元素。
如果有多個Context該怎麼做呢?我們在建立一個 Context
const OnLineContext = createContext();
如果有多個context變數的話,只需要把Privider巢狀進來即可,順序不重要。接下來宣告online的Provider了。
class App extends Component {
state = {
battery: 60,
online: false
}
render() {
const { battery, online } = this.state;
return (
<BatteryContext.Provider value={battery}>
<OnLineContext.Provider value={online} >
<button
type="button"
onClick={() => this.setState({ battery: battery - 1 })}
>
減減
</button>
<button
type="button"
onClick={() => this.setState({ online: !online })}
>
Switch
</button>
<Middle />
</OnLineContext.Provider>
</BatteryContext.Provider>
);
}
與Provider類似。Consumer也需要巢狀,順序不重要。只要Consumer需要宣告函式,所以要注意語法。
class Leaf extends Component {
render() {
return (
<BatteryContext.Consumer>
{
battery => (
<OnLineContext.Consumer>
{
online => <h1>Battery : {battery} , Online : {online.toString()}</h1>
}
</OnLineContext.Consumer>
)
}
</BatteryContext.Consumer>
)
}
}
全部程式碼:
import React, { Component, createContext } from 'react';
const BatteryContext = createContext();
const OnLineContext = createContext();
//宣告一個孫元件
class Leaf extends Component {
render() {
return (
//與Provider類似。Consumer也需要巢狀,順序不重要。只要Consumer需要宣告函式,所以要注意語法。
<BatteryContext.Consumer>
{
battery => (
<OnLineContext.Consumer>
{
online => <h1>Battery : {battery} , Online : {online.toString()}</h1>
}
</OnLineContext.Consumer>
)
}
</BatteryContext.Consumer>
)
}
}
//宣告一個子元件
class Middle extends Component {
render() {
return <Leaf />
}
}
class App extends Component {
state = {
battery: 60,
online: false
}
render() {
const { battery, online } = this.state;
//接下來宣告online的Provider了。如果有多個context變數的話,只需要把Privider巢狀進來即可,順序不重要。
return (
<BatteryContext.Provider value={battery}>
<OnLineContext.Provider value={online} >
<button
type="button"
onClick={() => this.setState({ battery: battery - 1 })}
>
減減
</button>
<button
type="button"
onClick={() => this.setState({ online: !online })}
>
Switch
</button>
<Middle />
</OnLineContext.Provider>
</BatteryContext.Provider>
);
}
}
export default App;
效果圖:
還有一個問題 , 如果Consumer向上找不到對應的Provider怎麼辦?
其實即使找不到也不會報錯,而是顯示為空。那怎麼設定預設值呢?
那上面的demo舉例 ,剛才我們設定的battery為60。如果Consumer向上找不到BatteryContext.Provider的值,我們可以這樣設定預設值:
const BatteryContext = createContext(30);
這樣BatteryContext.Consumer向上找不到值,就會取預設值30。
context不僅僅只是可以傳數值,也可以傳函式。大家可以試試看。
最後再提示一下大家,不要濫用context,不然會影響元件的獨立性。 如果一個元件中只使用一個Context的話,就可以使用contextType代替Consumer。詳見https://www.cnblogs.com/littleSpill/p/11221817.html