React的組件協(xié)同使用實現(xiàn)方式
開發(fā)人員不用太過于關(guān)注UI層面的實現(xiàn)細(xì)節(jié),考慮最多的也就是組件與組件之間的數(shù)據(jù)通信了。那么,在React開發(fā)中,有哪些場景的組件協(xié)同?又如何去實現(xiàn)組件的協(xié)同使用呢?
組件的協(xié)同本質(zhì)上是對組件的一種組織、管理方式。
目的是使得系統(tǒng) 邏輯清晰、代碼模塊化、封裝細(xì)節(jié)、代碼可復(fù)用。
組件的協(xié)同分為兩種方式:嵌套、抽離、發(fā)布訂閱模式。
嵌套
組件嵌套的本質(zhì)就是父子關(guān)系,即為父組件和子組件之間的通信。
總的來說有兩種場景:
- 父子組件通信
- 兄弟組件通信
父子組件通信
首先我們先來看看最常用的一個手段,通過props屬性。以父子組件為例,父組件只需要將數(shù)據(jù)以props的方式傳遞給子組件,子組件可以直接通過this.props來獲取,比如:
// 父組件 Parent
export default class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: '傳給子組件的消息'
}
}
// 消息回調(diào)
onMessage(messageFromChildren) {
console.log(messageFromChildren);
}
render() {
const { message } = this.state;
return (
<div>
<Children message={ message } onMessage={ this.onMessage.bind(this) } />
</div>
);
}
}
// 子組件 Children
export default class Children extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
this.props.onMessage('來自子組件的消息');
}
render() {
const { message } = this.props;
return (
<div>
<p>{ message }</p>
<button onClick={ this.handleClick.bind(this) }>click</button>
</div>
);
}
}
當(dāng)然,如果Children子組件需要傳遞數(shù)據(jù)給到父組件,可以使用回調(diào)方式,父組件將方法的引用通過props傳遞給到子組件,如上代碼中的handleClick里調(diào)用了onMessage。當(dāng)父組件的state更新時,Children組件會重新渲染,使用最新的message數(shù)據(jù)。
bind的作用就是給函數(shù)增加默認(rèn)的參數(shù),第一個傳參將替代方法里面的this
兄弟組件通信
兄弟組件不能直接相互通信,需要通過父組件來中轉(zhuǎn)一下,進(jìn)行狀態(tài)提升。兄弟組件將需要共享的數(shù)據(jù)提升至共同的直接父組件中,然后就跟普通的父子組件通信一樣了。比如:
// 父組件 Parent
export default class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
messageFromA: '',
messageFromB: ''
}
}
onMessage(messageFromChildren, from) {
console.log(messageFromChildren);
this.setState({
[from == 'A' ? 'messageFromA' : 'messageFromB']: messageFromChildren
});
}
render() {
const { messageFromA, messageFromB} = this.state;
return (
<div>
<ChildrenA message={ messageFromB } onMessage={ this.onMessage.bind(this) } />
<ChildrenB message={ messageFromA } onMessage={ this.onMessage.bind(this) } />
</div>
);
}
}
// 子組件ChildrenA
export default class ChildrenA extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
this.props.onMessage('來自A子組件的消息', 'A');
}
render() {
const { message } = this.props;
return (
<div className="p-a b-a">
<p>{ message }</p>
<button onClick={this.handleClick.bind(this)}>clickA</button>
</div>
);
}
}
// 子組件 ChildrenB
export default class ChildrenB extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
this.props.onMessage('來自B子組件的消息', 'B');
}
render() {
const { message } = this.props;
return (
<div className="p-a b-a">
<p>{ message }</p>
<button onClick={this.handleClick.bind(this)}>clickB</button>
</div>
);
}
}

當(dāng)點擊clickA的時候,子組件B接收到了子組件A的消息,反之亦然。
通過props的組件通信比較簡單,但也有其自身的缺陷,當(dāng)組件層級大于3層時,這種方式就不適合了,首先是深層級的傳遞對到維護(hù)來說簡直就是噩夢,需要一層一層的看才能知道數(shù)據(jù)的來源及流向。其次的話,假如不止A、B子組件,還有C子組件的,A、B組件引發(fā)的父組件state更新會觸發(fā)C子組件的更新,但事實上,C子組件并沒有接收任何數(shù)據(jù),容易造成資源浪費。
// Parent組件
render() {
const { messageFromA, messageFromB} = this.state;
return (
<div>
<ChildrenA message={ messageFromB } onMessage={ this.onMessage.bind(this) } />
<ChildrenB message={ messageFromA } onMessage={ this.onMessage.bind(this) } />
<ChildrenC />
</div>
);
}
// 子組件 ChildrenC
export default class ChildrenC extends React.Component {
constructor(props) {
super(props);
}
componentDidUpdate() {
console.log('ChildrenC updated');
}
render() {
return (
<div>ChildrenC</div>
);
}
}
抽離
Mixin
這里要介紹的抽離主要是指Mixin。
假設(shè)有多個組件使用相同的getDefaultProps方法,我們就可以定義如下Mixin:
var DefaultNameMixin = {
getDefaultProps: function () {
return {name: "Tom"};
}
};
Mixin相當(dāng)于組件的一個擴(kuò)展,它的本質(zhì)就是一組方法的集合,使用這個 mixin 的組件能夠自由的使用這些方法(就像在組件中定義的一樣)。使用Mixin的目的就是橫向抽離出組件的相似代碼。
與Mixin思路相似的概念還有:AOP、插件等
例子中,DefaultNameMixin中包含getDefaultProps方法。除了直接定義外,Mixin還可以嵌套使用,也就是可以在定義Mixin時使用另一個Mixin:
var DefaultCommonMixin = {
mixins:[DefaultNameMixin], //use Mixin
getDefaultProps: function () {
return {food: "rice"};
}
};
例子中,在DefaultCommonMixin的定義中嵌套使用了DefaultNameMixin,因此DefaultCommonMixin包含了DefaultNameMixin中定義的getDefaultProps方法,此時DefaultCommonMixin中有兩個方法。使用Mixin時,只需將Mixin加入到mixins屬性對應(yīng)的數(shù)組中,Mixin的使用語法為mixins:[Mixin1,Mixin2……]。
使用Mixin時,只需將Mixin加入到mixins屬性對應(yīng)的數(shù)組中,Mixin的使用語法為mixins:[Mixin1,Mixin2……]。
var Component = React.createClass({
mixins:[DefaultCommonMixin], //use Mixin
render:function(){
return <h1>{this.props.name} like {this.props.food}</h1>;
}
});
ReactDOM.render(
<Component/>,
document.getElementById("example")
);
一個組件可以使用多個Mixin,同時,Mixin也可使用在多個組件中。
使用Mixin時,需要注意不要在多個地方設(shè)置相同的Prop和State。同時,在不同的Mixin中定義相同的方法,或者M(jìn)ixin和組件中包含了相同的方法時,也會拋出異常,但是這種情況對componentDidMount等生命周期方法不適用(render方法除外,多次定義render方法也會拋出異常)。
如果在一個組件的多個地方定義了相同的生命周期方法,這些方法的執(zhí)行順序為:Mixin中的方法會優(yōu)先執(zhí)行(根據(jù)mixins中的順序從左到右的順序),然后執(zhí)行組件中定義的方法。
Mixin的優(yōu)點:
代碼復(fù)用:抽離出通用代碼,減少開發(fā)成本,提高開發(fā)效率
即插即用:可以直接使用許多現(xiàn)有的Mixin來編寫自己的組件
適應(yīng)性強(qiáng):改動一次代碼,影響多個組件
Mixin的缺點:
編寫難度高:Mixin可能被用在各種環(huán)境中,兼容多種環(huán)境就需要更多的邏輯和代碼,通用的代價是提高復(fù)雜度。
降低代碼可讀性:組件的優(yōu)勢在于將邏輯和界面直接結(jié)合在一起,Mixin本質(zhì)上會分散邏輯,理解起來難度更大。
React的LinkedStateMixin
'use strict';
// 構(gòu)建對象{value,requestChange},value為初始值,requestChange為方法,須手動調(diào)用
// 在本模塊中,value為state[key]的初始值,requestChange用于更新state[key]
var ReactLink = require('./ReactLink');
// 設(shè)定屬性key后,返回函數(shù),該函數(shù)接受value,內(nèi)部調(diào)用組件component.setState方法,更新state[key]=value
var ReactStateSetters = require('./ReactStateSetters');
/**
* 針對react手動調(diào)用setState方法的單向數(shù)據(jù)流,提供雙向綁定
* 使用linkState(key).requestChange(value)傳值后自動調(diào)用setState方法,更新state
*
* 示例
* var LinkedStateMixin = require('react-addons-linked-state-mixin');
* var WithoutLink = React.createClass({
* mixins: [LinkedStateMixin],
* getInitialState: function() {
* return {message: 'Hello!'};
* },
* render: function() {
* var valueLink = this.linkState('message');
* var handleChange = function(e) {
* valueLink.requestChange(e.target.value);
* };
* return <input type="text" value={valueLink.value} onChange={handleChange} />;
* }
* });
*/
var LinkedStateMixin = {
// ReactStateSetters.createStateKeySetter方法用于構(gòu)建linkState(key)返回對象的requestChange方法
// 實現(xiàn)傳值后自動調(diào)用setState方法,更新state
linkState: function (key) {
return new ReactLink(this.state[key], ReactStateSetters.createStateKeySetter(this, key));
}
};
module.exports = LinkedStateMixin;
使用上述的Mixin:
import LinkedStateMixin from 'react-addons-linked-state-mixin' mixins: [React.addons.LinkedStateMixin],
LinkedStateMixin僅僅是一個onChange/setState()模式的簡單包裝和約定。它不會從根本上改變數(shù)據(jù)在你的React應(yīng)用中如何流動,也就是說其實LinkedStateMixin本質(zhì)還是單向流,只是通過onChange將數(shù)據(jù)更改傳遞給React,然后內(nèi)部數(shù)據(jù)改變就自動調(diào)用setState來進(jìn)行更新。
使用示例:
var WithLink = React.createClass({
mixins: [LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={this.linkState('message')} />;
}
});
LinkedStateMixin給你的React組件添加一個叫做linkState()的方法。linkState()返回一個包含React state當(dāng)前的值和用來改變它的回調(diào)函數(shù)的valueLink對象。
valueLink 對象可以在樹中作為props被向上傳遞或者向下傳遞,所以它在組件層和狀態(tài)層建立起雙向綁定是非常簡單的。
注意:
對于checkbox的value屬性,有一個特殊的行為,如果checkbox被選中(默認(rèn)是on),value屬性值將會在表單提交的時候發(fā)送出去。當(dāng)checkbox被選中或者取消選中的時候,value屬性是不會更新的。對于checkbox,你應(yīng)該使用checkLink而不是valueLink。
<checkbox type="checkbox" checkedLink={this.linkState('booleanValue')} />
Reference:
1. http://schifred.iteye.com/blog/2361478
2. http://blog.csdn.net/qq_18661257/article/details/68951561
到此這篇關(guān)于React的組件協(xié)同使用的文章就介紹到這了,更多相關(guān)React組件協(xié)同內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React報錯之Object?is?possibly?null的問題及解決方法
這篇文章主要介紹了React報錯之Object?is?possibly?null的問題,造成 "Object is possibly null"的錯誤是因為useRef()鉤子可以傳遞一個初始值作為參數(shù),而我們傳遞null作為初始值,本文給大家分享詳細(xì)解決方法,需要的朋友可以參考下2022-07-07
解決React報錯Encountered?two?children?with?the?same?key
這篇文章主要為大家介紹了React報錯Encountered?two?children?with?the?same?key解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
React中實現(xiàn)keepalive組件緩存效果的方法詳解
由于react官方并沒有提供緩存組件相關(guān)的api(類似vue中的keepalive),在某些場景,會使得頁面交互性變的很差。所以本文為大家介紹了React中實現(xiàn)keepalive組件緩存效果的方法,希望對大家有所幫助2023-01-01
從零開始最小實現(xiàn)react服務(wù)器渲染詳解
這篇文章主要介紹了從零開始最小實現(xiàn)react服務(wù)器渲染詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
在 React 中使用 Redux 解決的問題小結(jié)
在 React 中組件通信的數(shù)據(jù)流是單向的,頂層組件可以通過 props 屬性向下層組件傳遞數(shù)據(jù),而下層組件不能直接向上層組件傳遞數(shù)據(jù),這篇文章主要介紹了使用react+redux實現(xiàn)彈出框案例,需要的朋友可以參考下2022-10-10

