搜尋
首頁web前端js教程傳統組件間通訊與React組件間通訊的分析比較(程式碼範例)

本篇文章帶給大家的內容是關於傳統組件間通訊與React組件間通訊的分析對比(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

在React中最小的邏輯單元是組件,組件之間如果有耦合關係就會進行通信,本文將會介紹React中的組件通信的不同方式

通過歸納範,可以將任意組件間的通信歸類為四種類型的組件間通信,分別是父子組件,爺孫組件,兄弟組件和任意組件,
需要注意的是前三個也可以算作任意組件的範疇,所以最後一個是萬能方法

父子組件

父子組件間的通信分為父組件向子組件通信和子組件向父組件通信兩種情況,下面先來介紹父元件向子元件通信,
傳統做法分為兩種情況,分別是初始化時的參數傳遞和實例階段的方法調用,例子如下

class Child {
    constructor(name) {
        // 获取dom引用
        this.$p = document.querySelector('#wp');

        // 初始化时传入name
        this.updateName(name);
    }
    updateName(name) {
        // 对外提供更新的api
        this.name = name;
    
        // 更新dom
        this.$p.innerHTML = name;
    }
}

class Parent {
    constructor() {
        // 初始化阶段
        this.child = new Child('yan');
        
        setTimeout(() => {
            // 实例化阶段
            this.child.updateName('hou');
        }, 2000);
    }
}

在React中將兩個情況統一處理,全部透過屬性來完成,之所以能夠這樣是因為React在屬性更新時會自動重新渲染子元件,
下面的範例中,2秒後子元件會自動重新渲染,並取得新的屬性值

class Child extends Component {
    render() {
        return <p>{this.props.name}</p>
    }
}

class Parent extends Component {
    constructor() {
        // 初始化阶段
        this.state = {name: 'yan'};

        setTimeout(() => {
            // 实例化阶段
            this.setState({name: 'hou'})
        }, 2000);
    }
    render() {
        return <child></child>
    }
}

下面來看子元件如何向父元件通信,傳統做法有兩種,一種是回呼函數,另一種是為子元件部署訊息介面

先來看回呼函數的例子,回呼函數的優點是非常簡單,缺點就是必須在初始化的時候傳入,並且不可撤回,並且只能傳入一個函數

class Child {
    constructor(cb) {
        // 调用父组件传入的回调函数,发送消息
        setTimeout(() => { cb() }, 2000);
    }
}

class Parent {
    constructor() {
        // 初始化阶段,传入回调函数
        this.child = new Child(function () {
            console.log('child update')
        });
    }
}

下面來看看訊息介面方法,首先需要一個可以發布和訂閱訊息的基類,例如下面實作了一個簡單的EventEimtter,實際生產中可以直接使用別人寫好的類別庫,例如@jsmini/event,子元件繼承訊息基類,就有了發布訊息的能力,然後父元件訂閱子元件的訊息,即可實現子元件向父元件通訊的功能

訊息介面的優點就是可以隨處訂閱,並且可以多次訂閱,還可以取消訂閱,缺點是略顯麻煩,需要引入訊息基底類別

// 消息接口,订阅发布模式,类似绑定事件,触发事件
class EventEimtter {
    constructor() {
        this.eventMap = {};
    }
    sub(name, cb) {
        const eventList = this.eventMap[name] = this.eventMap[name] || {};
        eventList.push(cb);
    }
    pub(name, ...data) {
        (this.eventMap[name] || []).forEach(cb => cb(...data));
    }
}

class Child extends EventEimtter {
    constructor() {
        super();
        // 通过消息接口发布消息
        setTimeout(() => { this.pub('update') }, 2000);
    }
}

class Parent {
    constructor() {
        // 初始化阶段,传入回调函数
        this.child = new Child();
        
        // 订阅子组件的消息
        this.child.sub('update', function () {
            console.log('child update')
        });
    }
}

Backbone.js就同時支援回呼函數和訊息介面方式,但React中選擇了比較簡單的回呼函數模式,下面來看一下React的例子

class Child extends Component {
    constructor(props) {
        setTimeout(() => { this.props.cb() }, 2000);
    }
    render() {
        return <p></p>
    }
}

class Parent extends Component {
    render() {
        return <child> {console.log('update')}} />
    }
}</child>

爺爺組件

#父子組件其實可以算是爺爺組件的一種特例,這裡的爺爺組件不光指爺爺和孫子,而是泛指祖先與後代組件通信,可能隔著很多層級,我們已經解決了父子組件通信的問題,根據化歸法,很容易得出爺孫組件的答案,那就是層層傳遞屬性麼,把爺孫組件通信分解為多個父子元件通訊的問題

層層傳遞的優點是非常簡單,用已有知識就能解決,問題是會浪費很多程式碼,非常繁瑣,中間作為橋樑的元件會引入很多不屬於自己的屬性

在React中,透過context可以讓祖先組件直接把屬性傳遞到後代組件,有點類似星際旅行中的蟲洞一樣,透過context這個特殊的橋樑,可以跨越任意層次向後代元件傳遞訊息

怎麼在需要通訊的元件之間開啟這個蟲洞呢?需要雙向聲明,也就是在祖先組件聲明屬性,並在後代組件上再次聲明屬性,然後在祖先組件上放上屬性就可以了,就可以在後代組件讀取屬性了,下面看一個例子

import PropTypes from 'prop-types';

class Child extends Component {
    // 后代组件声明需要读取context上的数据
    static contextTypes = {
        text: PropTypes.string
    }
    render() {
        // 通过this.context 读取context上的数据
        return <p>{this.context.text}</p>
    }
}


class Ancestor extends Component {
    // 祖先组件声明需要放入context上的数据
    static childContextTypes = {
        text: PropTypes.string
    }
    // 祖先组件往context放入数据
    getChildContext() {
        return {text: 'yanhaijing'}
    }
}

context的優點是可以省去層層傳遞的麻煩,並且透過雙向宣告控制了資料的可見性,對於層數很多時,不失為一種方案;但缺點也很明顯,就像全域變數一樣,如果不加節制很容易造成混亂,而且也容易出現重名覆蓋的問題

個人的建議是對一些所有組件共享的只讀信息可以採用context來傳遞,比如登錄的用戶信息等

小貼士:React Router路由就是透過context來傳遞路由屬性的

兄弟元件

如果兩個元件是兄弟關係,可以透過父元件作為橋樑,來讓兩個元件之間通信,這其實就是主模組模式

下面的例子中,兩個子元件透過父元件來實現顯示數字同步的功能

class Parent extends Component {
    constructor() {
        this.onChange = function (num) {
            this.setState({num})
        }.bind(this);
    }
    render() {
        return (
            <p>
                <child1>
                <child2>
            </child2></child1></p>
        );
    }
}

主模組模式的優點就是解耦,把兩個子組件之間的耦合關係,解耦成子組件和父組件之間的耦合,把分散的東西收集在一起好處非常明顯,能帶來更好的可維護性和可擴展性

任意元件

任意元件包含上面的三種關係元件,上面三種關係應該優先使用上面介紹的方法,對於任意的兩個元件間通信,總共有三種辦法,分別是共同祖先法,訊息中間件和狀態管理

基于我们上面介绍的爷孙组件和兄弟组件,只要找到两个组件的共同祖先,就可以将任意组件之间的通信,转化为任意组件和共同祖先之间的通信,这个方法的好处就是非常简单,已知知识就能搞定,缺点就是上面两种模式缺点的叠加,除了临时方案,不建议使用这种方法

另一种比较常用的方法是消息中间件,就是引入一个全局消息工具,两个组件通过这个全局工具进行通信,这样两个组件间的通信,就通过全局消息媒介完成了

还记得上面介绍的消息基类吗?下面的例子中,组件1和组件2通过全局event进行通信

class EventEimtter {
    constructor() {
        this.eventMap = {};
    }
    sub(name, cb) {
        const eventList = this.eventMap[name] = this.eventMap[name] || {};
        eventList.push(cb);
    }
    pub(name, ...data) {
        (this.eventMap[name] || []).forEach(cb => cb(...data));
    }
}

// 全局消息工具
const event = new EventEimtter;

// 一个组件
class Element1 extends Component {
    constructor() {
        // 订阅消息
        event.sub('element2update', () => {console.log('element2 update')});
    }
}

// 另一个组件。
class Element2 extends Component {
    constructor() {
        // 发布消息
        setTimeout(function () { event.pub('element2update') }, 2000)
    }
}

消息中间件的模式非常简单,利用了观察者模式,将两个组件之间的耦合解耦成了组件和消息中心+消息名称的耦合,但为了解耦却引入全局消息中心和消息名称,消息中心对组件的侵入性很强,和第三方组件通信不能使用这种方式

小型项目比较适合使用这种方式,但随着项目规模的扩大,达到中等项目以后,消息名字爆炸式增长,消息名字的维护成了棘手的问题,重名概率极大,没有人敢随便删除消息信息,消息的发布者找不到消息订阅者的信息等

其实上面的问题也不是没有解决办法,重名的问题可以通过制定规范,消息命名空间等方式来极大降低冲突,其他问题可以通过把消息名字统一维护到一个文件,通过对消息的中心化管理,可以让很多问题都很容易解决

如果你的项目非常大,上面两种方案都不合适,那你可能需要一个状态管理工具,通过状态管理工具把组件之间的关系,和关系的处理逻辑从组建中抽象出来,并集中化到统一的地方来处理,Redux就是一个非常不错的状态管理工具

除了Redux,还有Mobx,Rematch,reselect等工具,本文不展开介绍,有机会后面单独成文,这些都是用来解决不同问题的,只要根据自己的场景选择合适的工具就好。

以上是傳統組件間通訊與React組件間通訊的分析比較(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境