引言
在我們React組件開發中,當一個父組件的想要往自己的子孫組件傳值的時候,可以使用 props
屬性,但是其每一個子組件,都要向下傳遞數據,這樣造成的數據的耦合性,所以在 React 官方文檔中 提供了 context
特性來解決,這個問題。
父子組件之間的通信
我們先看一下React中,父子組件通信的機制,父子組件的通信是通過props進行數據的傳遞:
- 父組件向子組件傳遞數據(狀態)時,是在調用子組件的時候通過參數傳遞給子組件,子組件通過this.props進行接收;
- 子組件如果更改父組件的一些屬性,則是通過父組件定義的方法來傳遞給子組件,子組件調用更改;
- 如果父組件想要更改子組件的一些狀態時,通過ref進行標記,可以獲取子組件的所有信息,從而調用子組件的方法和值;
但是,如果層級很多呢,是否需要多個props進行逐層的傳遞?答案是否定的,React的advanced(高級)中指出了context,優雅的解決這個問題。
好的,接下來我們來介紹一下這個特性Context
我們知道,在JS中context指的是函數的執行上下文,函數被調用時,this指向誰,誰就是當前的執行上下文;
- react中的context是什么呢?官方文檔給出:
- Context 通過組件樹提供了一個傳遞數據的方法,從而避免了在每一個層級手動的傳遞 props 屬性。
文檔也沒具體給出context到底是什么,而是告訴我們context能干什么,也就是說,如果我們不想通過props實現組件樹的逐層傳遞數據,則可以使用context實現跨層級進行數據傳遞!
如何使用 Context 呢?
context api給出三個概念:React.createContext()、Provider、Consumer;
- React.createContext()
這個方法用來創建context對象,並包含Provider、Consumer兩個組件 <Provider />、<Consumer />
const {Provider, Consumer} = React.createContext();
- Provider
數據的生產者,通過value屬性接收存儲的公共狀態,來傳遞給子組件或后代組件
eg:
<Provider value={/* some value */}>
- Consumer
數據的消費者,通過訂閱Provider傳入的context的值,來實時更新當前組件的狀態
eg:
<Consumer>
{value => /* render something based on the context value */}
</Consumer>
值得一提的是每當Provider的值發生改變時, 作為Provider后代的所有Consumers都會重新渲染
props單向數據流動:
如果覺得Props傳遞數據很繁瑣,可以采用context,進行跨組件傳遞數據
再最外層的組件上,通過生產者Provider組件進行包裹,並存儲共享數據到value中,當然可以是任何數據類型。后帶需要用到共享數據的組件均可通過Consumer進行數據獲取
代碼演示
import React from 'react'
import ReactDOM from 'react-dom'
// 創建一個 textcont 特性的
const {Provider,Consumer} = React.createContext('頂頂頂')
class Person extends React.Component{
constructor(props){
super(props)
this.state = {
color : 'red'
}
}
render(){
return (
<Provider value={this.state.color}>
<h1>我是父組件</h1>
<Son></Son>
</Provider>
);
}
}
class Son extends Person{
render(){
return <div>
<h3>我是子組件</h3>
<Son1></Son1>
</div>
}
}
class Son1 extends Son{
render(){
return (
<Consumer>
{
(color) => <div>
<h6 style={{color}}>我是孫子組件-----{color}</h6>
</div>
}
</Consumer>
);
}
}
ReactDOM.render(<div>
<Person></Person>
</div>,document.getElementById('app'))