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