父子組件通信
顧名思義就是父組件和子組件之間進行通信交流。下面先看樣例代碼:
// 父子組件通信
import React from "react";
// 下面爲父子組件通信實例代碼
// 父組件
class ParentSon extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: "father",
name: "partent",
age: 60
};
}
callback = (msg, name, age) => {
this.setState({ msg });
this.setState({ name });
this.setState({ age });
};
render() {
return (
<div style={{padding: 30+'px'}}>
<h1>{this.state.msg}</h1>
<Child
callback={this.callback}
age={this.state.age}
name={this.state.name}
></Child>
</div>
);
}
}
// 子組件
class Child extends React.Component{
constructor(props){
super(props);
this.state={
msg: 'I am son',
name: 'son',
age: 8
};
// 下面一行代碼是爲了解決非箭頭函數使用時this的指向問題不能指向當前子組件自身
// this.change=this.change.bind(this);
}
// change(){
// // console.log(this);
// this.props.callback(this.state.msg,this.state.name,this.state.age);
// }
change=()=>{
this.props.callback(this.state.msg,this.state.name,this.state.age);
}
render(){
return (
<div>
<div>{this.props.name}</div>
<div>{this.props.age}</div>
<button onClick={this.change}>點擊</button>
</div>
)
}
}
export default ParentSon;
如上面代碼所示,分別創建了父組件 ParentSon 和子組件 Child ,父組件裏面定義了自己的state內容,並定義了一個 callback 方法,此方法用來改變父組件自身的state內容值的,然後render函數裏面除了渲染自身state裏的msg值之外,將自身的callback方法以及自身state裏的name,age分別作爲參數傳給了子組件 Child。
下面再繼續看子組件內部,除了有自己的state之外,還有一個change方法,然後render函數裏渲染了來自props裏的值以及一個點擊事件按鈕,而這個按鈕點擊事件就會觸發調用自身那個change事件,在進入change方法內部會看到,實際上,執行的就是props接收的callback方法,也就是從父組件傳過來的那個callback,而這裏的參數又是子組件自身state的內容值,到此,我們可以順一下整個思路了。
思路: 一開始渲染出的全是父組件的值(因爲子組件顯示的就是來自父組件的值)-----> 點擊按鈕 -----> 觸發子組件change事件(實際接收的父組件callback方法)-----> 父組件callback被調用,父組件的state裏的值都發生改變,此時已變成和子組件state裏一樣的值了 -----> state改變後的值,又通過props傳給了子組件Child -----> 再一次渲染出來傳過來的值,即和子組件一模一樣的值,此時整個過程全部結束。
跨級組件通信
顧名思義就是互不相干且之間隔了好幾級的一種通信交流方式。下面先看樣例代碼:
// 跨級組件通信
import React from "react";
const ThemeContext = React.createContext("light");
class ContextMess extends React.Component {
static contextType = ThemeContext;
render() {
return (
<ThemeContext.Provider value="dark">
<div style={{padding: 30+'px'}}>
<h3>{this.context}</h3>
<Toolbar></Toolbar>
</div>
</ThemeContext.Provider>
);
}
}
class Toolbar extends React.Component {
render() {
return (
<div>
<ThemedButton></ThemedButton>
</div>
);
}
}
class ThemedButton extends React.Component {
static contextType = ThemeContext;
render() {
return (
<div>
<h1>{this.context}</h1>
<ThemeContext.Consumer>
{value => (<h6>{value}</h6>)}
</ThemeContext.Consumer>
</div>
);
}
}
export default ContextMess;
從上面代碼可以看出,有三個組件,ContextMess ,Toolbar ,ThemedButton ,ContextMess 爲最外層組件,依次是Toolbar 組件,再是ThemedButton 組件,逐層嵌套。
代碼中主要使用了react中的Context技術點,使用了Context中的以下幾個API:React.createContext,Context.Provider,Class.contextType,Context.Consumer。
React.createContext: 創建一個 Context 對象。當 React 渲染一個訂閱了這個 Context 對象的組件,這個組件會從組件樹中離自身最近的那個匹配的 Provider 中讀取到當前的 context 值。
Context.Provider: 每個 Context 對象都會返回一個 Provider React 組件,它允許消費組件訂閱 context 的變化;Provider 接收一個 value 屬性,傳遞給消費組件;當 Provider 的 value 值發生變化時,它內部的所有消費組件都會重新渲染。
Class.contextType: (代碼中通過 static 來定義靜態屬性contextType,即組件(class)自己的屬性,等同於class.contextType)掛載在 class 上的 contextType 屬性會被重賦值爲一個由 React.createContext() 創建的 Context 對象。這能讓你使用 this.context 來消費最近 Context 上的那個值。你可以在任何生命週期中訪問到它,包括 render 函數中。
Context.Consumer: 這裏,React 組件也可以訂閱到 context 變更。這能讓你在函數式組件中完成訂閱 context;這需要函數作爲子元素(function as a child)這種做法。這個函數接收當前的 context 值,返回一個 React 節點。傳遞給函數的 value 值等同於往上組件樹離這個 context 最近的 Provider 提供的 value 值。如果沒有對應的 Provider,value 參數等同於傳遞給 createContext() 的 defaultValue。
思路: 簡單來說,那個‘light’一開始創建的就相當於要在其他組件使用的數據,在 ContextMess 組件中通過使用 contextType 獲取 createContext 創建的對象,然後通過this.context來獲取值,即“light”;除此之外,使用 Context.Provider API 通過value參數將當前值改爲“dark”,然後不使用 props 傳值方式,在二級組件中可以看到,並沒有使用props接收值,最後在下一級組件通過 Class.contextType 和 this.context 方式讀取值,除此之外還使用 Context.Consumer API 來獲取最近的那個匹配的context值,即改變後的值“dark”。