摘要:前言今天群里面有很多都在問關于組件之間是如何通信的問題,之前自己寫的時候也遇到過這類問題。英文能力有限,如果有不對的地方請跟我留言,一定修改原著序處理組件之間的交流方式,主要取決于組件之間的關系,然而這些關系的約定人就是你。
前言
今天群里面有很多都在問關于 React 組件之間是如何通信的問題,之前自己寫的時候也遇到過這類問題。下面是我看到的一篇不錯英文版的翻譯,看過我博客的人都知道,我翻譯可能不會按部就班,會盡可能用中文的意思,來將作者要講述的技術描述清楚。英文能力有限,如果有不對的地方請跟我留言,一定修改……^_^
原著序處理 React 組件之間的交流方式,主要取決于組件之間的關系,然而這些關系的約定人就是你。
我不會講太多關于 data-stores、data-adapters 或者 data-helpers 之類的話題。我下面只專注于 React 組件本身的交流方式的講解。
React 組件之間交流的方式,可以分為以下 3 種:
【父組件】向【子組件】傳值;
【子組件】向【父組件】傳值;
沒有任何嵌套關系的組件之間傳值(PS:比如:兄弟組件之間傳值)
一、【父組件】向【子組件】傳值初步使用
這個是相當容易的,在使用 React 開發的過程中經常會使用到,主要是利用 props 來進行交流。例子如下:
// 父組件 var MyContainer = React.createClass({ getInitialState: function () { return { checked: true }; }, render: function() { return (); } }); // 子組件 var ToggleButton = React.createClass({ render: function () { // 從【父組件】獲取的值 var checked = this.props.checked, text = this.props.text; return ( ); } });
進一步討論
如果組件嵌套層次太深,那么從外到內組件的交流成本就變得很高,通過 props 傳遞值的優勢就不那么明顯了。(PS:所以我建議盡可能的減少組件的層次,就像寫 HTML 一樣,簡單清晰的結構更惹人愛)
// 父組件 var MyContainer = React.createClass({ render: function() { return (二、【子組件】向【父組件】傳值); } }); // 子組件1:中間嵌套的組件 var Intermediate = React.createClass({ render: function () { return ( ); } }); // 子組件2:子組件1的子組件 var Child = React.createClass({ render: function () { return ( {this.props.text} ); } });
接下來,我們介紹【子組件】控制自己的 state 然后告訴【父組件】的點擊狀態,然后在【父組件】中展示出來。因此,我們添加一個 change 事件來做交互。
// 父組件 var MyContainer = React.createClass({ getInitialState: function () { return { checked: false }; }, onChildChanged: function (newState) { this.setState({ checked: newState }); }, render: function() { var isChecked = this.state.checked ? "yes" : "no"; return (); } }); // 子組件 var ToggleButton = React.createClass({ getInitialState: function () { return { checked: this.props.initialChecked }; }, onTextChange: function () { var newState = !this.state.checked; this.setState({ checked: newState }); // 這里要注意:setState 是一個異步方法,所以需要操作緩存的當前值 this.props.callbackParent(newState); }, render: function () { // 從【父組件】獲取的值 var text = this.props.text; // 組件自身的狀態數據 var checked = this.state.checked; return ( ); } });Are you checked: {isChecked}
我覺得原文作者用代碼不是很直觀,接下來我話一個流程走向簡圖來直觀描述一下這個過程:
這樣做其實是依賴 props 來傳遞事件的引用,并通過回調的方式來實現的,這樣實現不是特別好,但是在沒有任何工具的情況下也是一種簡單的實現方式
這里會出現一個我們在之前討論的問題,就是組件有多層嵌套的情況下,你必須要一次傳入回調函數給 props 來實現子組件向父組件傳值或者操作。
Tiny-Tip: React Event System在 onChange 事件或者其他 React 事件中,你能夠獲取以下東西:
【this】:指向你的組件
【一個參數】:這個參數是一個 React 合成事件,SyntheticEvent。
React 對所有事件的管理都是自己實現的,與我們之前使用的 onclick、onchange 事件不一樣。從根本上來說,他們都是綁定到 body 上。
document.on("change", "input[data-reactid=".0.2"]", function () {...});
上面這份代碼不是來自于 React,只是打一個比方而已。
如果我沒有猜錯的話,React 真正處理一個事件的代碼如下:
var listenTo = ReactBrowserEventEmitter.listenTo; ... function putListener(id, registrationName, listener, transaction) { ... var container = ReactMount.findReactContainerForID(id); if (container) { var doc = container.nodeType === ELEMENT_NODE_TYPE ? container.ownerDocument : container; listenTo(registrationName, doc); } ... } // 在監聽事件的內部,我們能發現如下: target.addEventListener(eventType, callback, false);
這里有所有 React 支持的事件:中文文檔-事件系統
多個子組件使用同一個回調的情況
// 父組件 var MyContainer = React.createClass({ getInitialState: function () { return { totalChecked: 0 }; }, onChildChanged: function (newState) { var newToral = this.state.totalChecked + (newState ? 1 : -1); this.setState({ totalChecked: newToral }); }, render: function() { var totalChecked = this.state.totalChecked; return (); } }); // 子組件 var ToggleButton = React.createClass({ getInitialState: function () { return { checked: this.props.initialChecked }; }, onTextChange: function () { var newState = !this.state.checked; this.setState({ checked: newState }); // 這里要注意:setState 是一個異步方法,所以需要操作緩存的當前值 this.props.callbackParent(newState); }, render: function () { // 從【父組件】獲取的值 var text = this.props.text; // 組件自身的狀態數據 var checked = this.state.checked; return ( ); } });How many are checked: {totalChecked}
這是非常容易理解的,在父組件中我們增加了一個【totalChecked】來替代之前例子中的【checked】,當子組件改變的時候,使用同一個子組件的回調函數給父組件返回值。
三、沒有任何嵌套關系的組件之間傳值如果組件之間沒有任何關系,組件嵌套層次比較深(個人認為 2 層以上已經算深了),或者你為了一些組件能夠訂閱、寫入一些信號,不想讓組件之間插入一個組件,讓兩個組件處于獨立的關系。對于事件系統,這里有 2 個基本操作步驟:訂閱(subscribe)/監聽(listen)一個事件通知,并發送(send)/觸發(trigger)/發布(publish)/發送(dispatch)一個事件通知那些想要的組件。
下面講介紹 3 種模式來處理事件,你能點擊這里來比較一下它們。
簡單總結一下:
(1) Event Emitter/Target/Dispatcher
特點:需要一個指定的訂閱源
// to subscribe otherObject.addEventListener(‘click’, function() { alert(‘click!’); }); // to dispatch this.dispatchEvent(‘click’);
(2) Publish / Subscribe
特點:觸發事件的時候,你不需要指定一個特定的源,因為它是使用一個全局對象來處理事件(其實就是一個全局
廣播的方式來處理事件)
// to subscribe globalBroadcaster.subscribe(‘click’, function() { alert(‘click!’); }); // to dispatch globalBroadcaster.publish(‘click’);
(3) Signals
特點:與Event Emitter/Target/Dispatcher相似,但是你不要使用隨機的字符串作為事件觸發的引用。觸發事件的每一個對象都需要一個確切的名字(就是類似硬編碼類的去寫事件名字),并且在觸發的時候,也必須要指定確切的事件。(看例子吧,很好理解)
// to subscribe otherObject.clicked.add(function() { alert(‘click’); }); // to dispatch this.clicked.dispatch();
如果你只想簡單的使用一下,并不需要其他操作,可以用簡單的方式來實現:
// 簡單實現了一下 subscribe 和 dispatch var EventEmitter = { _events: {}, dispatch: function (event, data) { if (!this._events[event]) { // 沒有監聽事件 return; } for (var i = 0; i < this._events[event].length; i++) { this._events[event][i](data); } }, subscribe: function (event, callback) { // 創建一個新事件數組 if (!this._events[event]) { this._events[event] = []; } this._events[event].push(callback); } }; otherObject.subscribe("namechanged", function(data) { alert(data.name); }); this.dispatch("namechanged", { name: "John" });
如果你想使用 Publish/Subscribe 模型,可以使用:PubSubJS
React 團隊使用的是:js-signals 它基于 Signals 模式,用起來相當不錯。
Events in React使用 React 事件的時候,必須關注下面兩個方法:
componentDidMount componentWillUnmount
在處理事件的時候,需要注意:
在 componentDidMount 事件中,如果組件掛載(mounted)完成,再訂閱事件;當組件卸載(unmounted)的時候,在 componentWillUnmount 事件中取消事件的訂閱。
(如果不是很清楚可以查閱 React 對生命周期介紹的文檔,里面也有描述。原文中介紹的是 componentWillMount 個人認為應該是掛載完成后訂閱事件,比如Animation這個就必須掛載,并且不能動態的添加,謹慎點更好)
因為組件的渲染和銷毀是由 React 來控制的,我們不知道怎么引用他們,所以EventEmitter 模式在處理組件的時候用處不大。
pub/sub 模式可以使用,你不需要知道引用。
下面來一個例子:實現有多個 product 組件,點擊他們的時候,展示 product 的名字。
(我在例子中引入了之前推薦的 PubSubJS 庫,如果你覺得引入代價太大,也可以手寫一個簡版,還是比較容易的,很好用哈,大家也可以體驗,但是我還是不推薦全局廣播的方式)
// 定義一個容器 var ProductList = React.createClass({ render: function () { return (ES6: yield and js-csp); } }); // 用于展示點擊的產品信息容器 var ProductSelection = React.createClass({ getInitialState: function() { return { selection: "none" }; }, componentDidMount: function () { this.pubsub_token = PubSub.subscribe("products", function (topic, product) { this.setState({ selection: product }); }.bind(this)); }, componentWillUnmount: function () { PubSub.unsubscribe(this.pubsub_token); }, render: function () { return (You have selected the product : {this.state.selection}
); } }); var Product = React.createClass({ onclick: function () { PubSub.publish("products", this.props.name); }, render: function() { return{this.props.name}; } });
ES6 中有一種傳遞信息的方式,使用生成函數(generators)和 yield 關鍵字。可以看一下 https://github.com/ubolonton/js-csp
(這里我寫一個簡單的 DEMO 介紹一下這種新的傳遞方式,其實大同小異)
function* list() { for(var i = 0; i < arguments.length; i++) { yield arguments[i]; } return "done."; } var o = list(1, 2, 3); var cur = o.next; while(!cur.done) { cur = o.next(); console.log(cur); }
以上例子來自于屈屈的一篇博客:ES6 中的生成器函數介紹 屈屈是一個大牛,大家可以經常關注他的博客。
通常來說,你有一個隊列,對象在里面都能找到一個引用,在定義的時候鎖住,當發生的時候,立即打開鎖執行。js-csp 是一種解決辦法,也許以后還會有其他解決辦法。
結尾在實際應用中,按照實際要解決的需求選擇解決辦法。對于小應用程序,你可以使用 props 和回調的方法進行組件之間的數據交換。你可以通過 pub/sub 模式,以避免污染你的組件。在這里,我們不是在談論數據,只是組件。對于數據的請求、數據的變化等場景,可以使用 Facebook 的 Flux、Relay、GraphQL 來處理,都非常的好用。
文中的每一個例子我都驗證過了,主要使用最原始的引入文件方式,創建服務使用的 http-server 包,大家也可以嘗試自己來一次。
譯:英文原版
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78203.html
摘要:子組件請輸入郵箱父組件,此處通過獲取子組件的值用戶郵箱兄弟組件傳遞信息我們可以通過給這兩兄弟一個共同的父親,然后結合上面的兩種方法將老大的信息傳給父親子傳父,再通過父親傳給老二信息實現交流父傳子這里只寫出了父組件代碼實現到的數據傳遞 React 組件之間交流的方式,可以分為以下 3 種:a【父組件】向【子組件】傳值;b【子組件】向【父組件】傳值;c 沒有任何嵌套關系的組件之間傳值(PS...
摘要:小明小明兒子,可以看到組件顯示了父組件的。小明受控組件和非受控組件受控組件和非受控組件這些都是指的表單組件,當一個表單的值是通過改變的而不是通過是受控組件,否則就是非受控組件。 react眾所周知的前端3大主流框架之一,由于出色的性能,完善的周邊設施風頭一時無兩。本文就帶大家一起掌握react。 jsx語法 前端MVVM主流框架都有一套自己的模板處理方法,react則使用它獨特的jsx...
摘要:函數屬性或者說事件在組件之間通信過程中是必不可少的,但是切莫讓它影響了大家對單向數據流這一概念的理解。這應該屬于一種的使用方式,而且這樣做有悖單向數據流原則。 上一篇文章 玩轉 React(六)- 處理事件 介紹了在 React 中如何處理用戶事件,以及 React 事件機制與原生 DOM 事件的差異和注意的問題,同時也介紹了事件處理函數中 this 的指向問題以及處理的幾種方式及其優...
摘要:正如我們前面的教程所提到的,在組件之間流通數據更確切的說,這被叫做單向數據流數據沿著一個方向從父組件流到子組件。這就是如何使數據流變得更簡單的原因。它是一種傾向單向數據流比如的設計模式。這是因為總是接受和返回狀態用來更新。 前言 近期接觸React項目,學到許多新知識點,網上教程甚多,但大多都把知識點分開來講,初學者容易陷入學習的誤區,摸不著頭腦,本人在學習中也遇到許多坑。此篇文章是筆...
閱讀 2102·2021-11-19 09:58
閱讀 1701·2021-11-15 11:36
閱讀 2867·2019-08-30 15:54
閱讀 3386·2019-08-29 15:07
閱讀 2759·2019-08-26 11:47
閱讀 2805·2019-08-26 10:11
閱讀 2496·2019-08-23 18:22
閱讀 2744·2019-08-23 17:58