在咱們使用 React 中,不可避免的要進行組件之間的通訊(數據傳遞)。react
須要注意一點:React中數據的流動是單向的git
組件之間的數據傳遞大體分爲一下幾種:redux
父組件向子組件傳遞數據api
子組件向父組件傳遞數據數組
跨級組件之間傳遞數據(例如父組件向子子組件傳遞數據)bash
非嵌套組件之間傳遞數據app
下面咱們使用兩種方法 (props和context),分別寫段代碼來實現上面四種通訊的方式ide
總體通訊圖解:函數
運行效果:工具
props
通訊直接上代碼:
import React, { Component } from 'react';
class App extends Component {
state = { color: 'red' }
changeColor = color => {
this.setState({ color: color })
}
render() {
return (
<div style={{ border: `8px solid ${this.state.color}`, padding: "5px", margin: '5px' }}>
<h1>Wrapper</h1>
<Header color={this.state.color}></Header>
<Main changeColor={this.changeColor.bind(this)} color={this.state.color}></Main>
</div>
)
}
}
class Header extends Component {
render() {
return (
<div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
<h1>Header</h1>
<Title color={this.props.color}></Title>
</div>
)
}
}
class Title extends Component {
render() {
return (
<div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
<h1>Title</h1>
</div>
)
}
}
class Main extends Component {
render() {
return (
<div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
<h1>Main</h1>
<Content changeColor={this.props.changeColor} color={this.props.color}></Content>
</div>
)
}
}
class Content extends Component {
render() {
return (
<div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
<h1>Content</h1>
<button onClick={()=>this.props.changeColor("blue")}>變藍</button>
<button onClick={()=>this.props.changeColor("green")}>變綠</button>
</div>
)
}
}
export default App;
複製代碼
圖解:
context
通訊上面的代碼 想必也看到了不足,若是子子組件須要使用父組件的狀態,就須要逐級傳遞在組件中書寫傳遞代碼
而且這裏面還只是嵌套了兩級,組件也比較少,若是組件多,狀態多的話怎麼辦?
套會套會,就把本身給套迷了,因此使用上面方法很容易出現問題,因此在這裏咱們使用react中給咱們提供的api---Context來解決,也就是執行上下文
固然這也不是最優的解決方式,若是是大型項目的話,最好使用Redux來管理咱們的狀態,若是是小型項目的話,也不必使用Redux,由於React中自身也提供了狀態管理機制
上代碼:
import React, { Component } from 'react';
//利用react中提供的api建立一個上下文
let ColorContext = React.createContext();
// Context對象中提供了兩個api,一個是 Provider 提供數據
// 另外一個是Consumer, 獲取數據
// Context.Provder 是一個組件 Context.Provder就表示提供數據的
// static contextType = ColorContext; 加contextType主要就是用來校驗的,若是不校驗能夠不加
class App extends Component {
state = { color: 'red' }
changeColor = color => {
this.setState({ color: color })
}
render() {
//獲取數據到上下文中
let contextValue = { color: this.state.color, changeColor: this.changeColor }
return (
//使用咱們創造的上下文組件把咱們寫的組件所有包起來,並使用value綁定數據
<ColorContext.Provider value={contextValue}>
<div style={{ border: `8px solid ${this.state.color}`, padding: "5px", margin: '5px' }}>
<h1>Wrapper</h1>
{/* 在這裏咱們就就不須要綁定了 */}
<Header></Header>
<Main></Main>
</div>
</ColorContext.Provider>
)
}
}
class Header extends Component {
// 而後就須要在子組件中使用這個上下文提供的數據了
// 須要給類加上一個靜態屬性,值就是這個上下文,哪一個組件使用,那就必須加這個話
static contextType = ColorContext;
render() {
return (
// 這裏就須要用 this.context 了
<div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
<h1>Header</h1>
<Title></Title>
</div>
)
}
}
class Title extends Component {
static contextType = ColorContext;
render() {
return (
<div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
<h1>Title</h1>
</div>
)
}
}
class Main extends Component {
static contextType = ColorContext;
render() {
return (
<div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
<h1>Main</h1>
<Content></Content>
</div>
)
}
}
class Content extends Component {
static contextType = ColorContext;
render() {
return (
<div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
<h1>Content</h1>
<button onClick={() => this.context.changeColor("blue")}>變藍</button>
<button onClick={() => this.context.changeColor("green")}>變綠</button>
</div>
)
}
}
export default App;
複製代碼
圖解:
上面是在類組件中使用上下文,那麼若是不是類組件,是函數組件呢?該怎麼使用context(上下文)
這裏咱們把Main
的類組件換成函數組件:
import React, { Component } from 'react';
let ColorContext = React.createContext();
class App extends Component {
state = { color: 'red' }
changeColor = color => {
this.setState({ color: color })
}
render() {
let contextValue = { color: this.state.color, changeColor: this.changeColor }
return (
<ColorContext.Provider value={contextValue}>
<div style={{ border: `8px solid ${this.state.color}`, padding: "5px", margin: '5px' }}>
<h1>Wrapper</h1>
<Header></Header>
<Main></Main>
</div>
</ColorContext.Provider>
)
}
}
class Header extends Component {
static contextType = ColorContext;
render() {
return (
<div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
<h1>Header</h1>
<Title></Title>
</div>
)
}
}
class Title extends Component {
static contextType = ColorContext;
render() {
return (
<div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
<h1>Title</h1>
</div>
)
}
}
// class Main extends Component {
// static contextType = ColorContext;
// render() {
// return (
// <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
// <h1>Main</h1>
// <Content></Content>
// </div>
// )
// }
// }
function Main() {
return (
//須要使用ColorContext.Consumer包起來
<ColorContext.Consumer>
{
value => (
<div style={{ border: `8px solid ${value.color}`, padding: "5px", margin: '5px' }}>
<h1>Main</h1>
<Content></Content>
</div>
)
}
</ColorContext.Consumer>
)
}
class Content extends Component {
static contextType = ColorContext;
render() {
return (
<div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
<h1>Content</h1>
<button onClick={() => this.context.changeColor("blue")}>變藍</button>
<button onClick={() => this.context.changeColor("green")}>變綠</button>
</div>
)
}
}
export default App;
複製代碼
事實上,在組件間進行通訊時,這些通訊方式均可以使用,區別只在於使用相應的通訊方式的複雜程度和我的喜愛,選擇最合適的那一個。
固然,本身實現組件間的通訊仍是太難以管理了,所以出現了不少狀態管理工具,如 redux、mobx 等,使用這些工具使得組件間的通訊更容易追蹤和管理。