需要組件之進行通信的幾種情況:
- 父組件向子組件通信
- 子組件向父組件通信
- 跨級組件通信
- 沒有嵌套關系組件之間的通信
1. 父組件向子組件通信
React數(shù)據流動是單向的,父組件向子組件通信也是最常見的;父組件通過props向子組件傳遞需要的信息妖滔。
父組件:
<StrategyTable
maxLength={2}
styleName="strategy-able"
onRowClick={this.onRowClick}
delayTime={500}
isRefresh={false}
/>
子組件:
import PropTypes from 'prop-types';
static propTypes = {
maxLength: PropTypes.number,
isSignalStk: PropTypes.bool,
onRowClick: PropTypes.func,
getLastData: PropTypes.func,
onRef: PropTypes.func,
assetId: PropTypes.string,
sessionId: PropTypes.string,
isDataSeparate: PropTypes.bool,
delayTime: PropTypes.number,
isRefresh: PropTypes.bool,
}
static defaultProps = {
maxLength: -1,
isSignalStk: false,
onRowClick: () => {},
getLastData: () => {},
onRef: () => {},
assetId: '',
sessionId: '',
isDataSeparate: false,
delayTime: 0,
isRefresh: true,
}
constructor(props) {
super(props);
this.state = {
maxLength: this.props.maxLength, // 子組件通過 this.props.屬性名 來獲取父組件傳來的參數(shù)
};
}
2. 子組件向父組件通信
利用回調函數(shù)參數(shù)獲取子組件傳來的值邢锯。
父組件:
import React, { Component } from 'react';
export default class ListWrap extends Component {
getSunData = (val) => {
this.text = val;
}
render() {
return (
<div>
<sunComponent onRowClick={this.getSunData}/>
</div>
);
}
}
子組件:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class sunComponent extends Component {
static propTypes = {
onRowClick: PropTypes.func,
}
static defaultProps = {
onRowClick: () => {},
}
render() {
return (
<div>
<ul>
<li onClick={() => {this.props.onRowClick('子組件信息')}}>我是子組件信息</li>
</ul>
</div>
);
}
}
3. 跨級組件通信
跨級組件通信有兩種方法:
1. 層層傳遞props
例如A組件和B組件之間要進行通信,先找到A和B公共的父組件,A先向C組件通信,C組件通過props和B組件通信,此時C組件起的就是中間件的作用
2.使用context
context是一個全局變量,像是一個大容器,在任何地方都可以訪問到,我們可以把要通信的信息放在context上,然后在其他組件中可以隨意取到;
但是React官方不建議使用大量context,盡管他可以減少逐層傳遞,但是當組件結構復雜的時候,我們并不知道context是從哪里傳過來的;而且context是一個全局變量,全局變量正是導致應用走向混亂的罪魁禍首.
props傳參就不多說了鸠删,接下來重點說一下context。
對于父組件,也就是Context生產者遥昧,需要通過一個靜態(tài)屬性childContextTypes聲明提供給子組件的Context對象的屬性,并實現(xiàn)一個實例getChildContext方法,返回一個代表Context的純對象 (plain object) 鸥诽。
import React from 'react'
import PropTypes from 'prop-types'
class MiddleComponent extends React.Component {
render () {
return <ChildComponent />
}
}
class ParentComponent extends React.Component {
// 聲明Context對象屬性
static childContextTypes = {
propA: PropTypes.string,
methodA: PropTypes.func
}
// 返回Context對象,方法名是約定好的
getChildContext () {
return {
propA: 'propA',
methodA: () => 'methodA'
}
}
render () {
return <MiddleComponent />
}
}
而對于Context的消費者箕憾,通過如下方式訪問父組件提供的Context牡借。
import React from 'react'
import PropTypes from 'prop-types'
class ChildComponent extends React.Component {
// 聲明需要使用的Context屬性
static contextTypes = {
propA: PropTypes.string,
}
render () {
const {
propA,
methodA
} = this.context
console.log(`context.propA = ${propA}`) // context.propA = propA
console.log(`context.methodA = ${methodA}`) // context.methodA = undefined
return ...
}
}
子組件需要通過一個靜態(tài)屬性contextTypes聲明后,才能訪問父組件Context對象的屬性袭异,否則钠龙,即使屬性名沒寫錯,拿到的對象也是undefined御铃。
幾個可以直接獲取Context的地方:
實際上碴里,除了實例的context屬性(this.context),React組件還有很多個地方可以直接訪問父組件提供的Context上真。比如構造方法:
constructor(props, context)
比如生命周期:
componentWillReceiveProps(nextProps, nextContext)
shouldComponentUpdate(nextProps, nextState, nextContext)
componetWillUpdate(nextProps, nextState, nextContext)
4. 沒有嵌套關系的組件通信
在componentDidMount事件中,如果組件掛載完成,再訂閱事件;在組件卸載的時候,在componentWillUnmount事件中取消事件的訂閱;
以常用的發(fā)布/訂閱模式舉例,借用Node.js Events模塊的瀏覽器版實現(xiàn)咬腋。
下面例子中的組件關系: List1和List2沒有任何嵌套關系,App是他們的父組件;
實現(xiàn)這樣一個功能: 點擊List2中的一個按鈕,改變List1中的信息顯示
首先需要項目中安裝events 包:
npm install events --save
在src下新建一個util目錄里面建一個events.js
import { EventEmitter } from 'events';
export default new EventEmitter();
list1.jsx
import React, { Component } from 'react';
import emitter from '../util/events';
class List extends Component {
constructor(props) {
super(props);
this.state = {
message: 'List1',
};
}
componentDidMount() {
// 組件裝載完成以后聲明一個自定義事件
this.eventEmitter = emitter.addListener('changeMessage', (message) => {
this.setState({
message,
});
});
}
componentWillUnmount() {
emitter.removeListener(this.eventEmitter);
}
render() {
return (
<div>
{this.state.message}
</div>
);
}
}
export default List;
List2.jsx
import React, { Component } from 'react';
import emitter from '../util/events';
class List2 extends Component {
handleClick = (message) => {
emitter.emit('changeMessage', message);
};
render() {
return (
<div>
<button onClick={this.handleClick.bind(this, 'List2')}>
點擊我改變List1組件中顯示信息
</button>
</div>
);
}
}
APP.jsx
import React, { Component } from 'react';
import List1 from './components/List1';
import List2 from './components/List2';
export default class App extends Component {
render() {
return (
<div>
<List1 />
<List2 />
</div>
);
}
}
總結:
- 父組件向子組件通信: props
- 子組件向父組件通信: 回調函數(shù)
- 跨級組件通信: 層層組件傳遞props/context
- 沒有嵌套關系組件之間的通信: EventEmitter