react組件之間的通信

本文首發(fā)于公眾號(hào)【一個(gè)老碼農(nóng)】

react組件之間的通信颂暇,大致可以分為以下幾類

  • 父?jìng)髯?/li>
  • 子傳父
  • 兄弟組件之間的通信
  • 任意組件之間的通信
  • 數(shù)據(jù)全局共享

下面我就來(lái)正式聊一下react組件之間有哪些通信方式盖奈,并且都是怎樣進(jìn)行通信的活喊,宦言,語(yǔ)言我們用react + typescript

1.父?jìng)髯?/h2>
  • props

props傳遞數(shù)據(jù)是我們react開(kāi)發(fā)過(guò)程中最常用的一種方式敲茄,可以把父組件的數(shù)據(jù)傳遞給子組件焰檩,下面我們就用代碼演示一下:

父組件代碼:

import React from 'react';
import ChildA from './ChildA';

function App() {
  return (
    <div>
      <ChildA title='父?jìng)髯訑?shù)據(jù)'></ChildA>
    </div>
  )
}

export default App

子組件代碼:

interface ChildAProps {
    title: string
}
const ChildA: React.FC<ChildAProps> = ({title}) => {
    return <div>{title}</div>
}

export default ChildA
  • useContext

useContext傳遞的數(shù)據(jù)退客,在Context.Provider的所有子組件中都可以獲取到焚虱,value一旦更新购裙,所有子組件也會(huì)同步更新

父組件代碼:

import React from 'react';
import ChildB from './ChildB';

export const Context = React.createContext<String>('')

function App() {
  return (
    <Context.Provider value={'context傳值'}>
      <div>
       <ChildB></ChildB>
      </div>
    </Context.Provider>
  )
}

export default App

子組件代碼:

import { useContext } from "react"
import { Context } from "./App"

const ChildB = () => {

    const title = useContext(Context)

    return <div>
        這是ChildB {title}
    </div>
}

export default ChildB

2. 子傳父

  • Props回調(diào)函數(shù)

向子組件Props中傳一個(gè)函數(shù),在子組件需要向父組件傳遞數(shù)據(jù)時(shí)鹃栽,調(diào)用此函數(shù)即可

子組件代碼:

interface ChildAProps {
    title?: string
    call?: (param: string) => void
}
const ChildA: React.FC<ChildAProps> = ({title, call}) => {
    return <div onClick={()=>{
        call && call('回傳參數(shù)')
    }}>這是ChildA {title}</div>
}

export default ChildA

父組件代碼:

import React from 'react';
import ChildA from './ChildA';

function App() {
  return (
      <div>
       <ChildA call={(v)=>{
         console.log(`子組件傳過(guò)來(lái)的值 ${v}`)
       }}></ChildA>
      </div>
  )
}

export default App

  • useRef函數(shù)調(diào)用

ref的方式可以為父組件提供一個(gè)可以調(diào)用子組件的函數(shù)躏率,在子組件被調(diào)用的函數(shù)中可以返回相應(yīng)的數(shù)據(jù)至父組件,父組件則需要在子組件的Props中傳入一個(gè)ref

子組件代碼:

import { MutableRefObject, useImperativeHandle } from "react"

export interface ChildDCurrent {
    refresh: () => string
}

interface ChildDProps {
    cref: MutableRefObject<ChildDCurrent>
}

const ChildD: React.FC<ChildDProps> = ({cref}) => {

    useImperativeHandle(cref, ()=>({
        refresh: () => {
            return '123'
        }
    }))

    return <div></div>
}

export default ChildD

父組件代碼:

import { MutableRefObject, useRef } from "react"
import ChildD, { ChildDCurrent } from "./ChildD"

const ChildC = () => {

    const ref = useRef() as MutableRefObject<ChildDCurrent>

    return <div>
        <button onClick={()=> {
            // ChildD傳過(guò)來(lái)的數(shù)據(jù)
            const title = ref.current.refresh()
            console.log(`子組件傳遞過(guò)來(lái)的數(shù)據(jù) ${title}`)
        }}>
            點(diǎn)擊刷新
        </button>
        <ChildD cref={ref}></ChildD>
    </div>
}

export default ChildC

3.兄弟組件之間的通信

兄弟組件之間的數(shù)據(jù)傳遞民鼓,可以利用組件的Props以及Props回調(diào)函數(shù)來(lái)進(jìn)行薇芝,而這種使用方法通信的前提是:必須要有共同的父組件

子組件代碼:

interface ChildFProps {
    update: (title: string) => void
}
const ChildF: React.FC<ChildFProps> = ({update}) => {
    return <div onClick={() => {
        update('abcde')
    }}>ChildF</div>
}
export default ChildF


interface ChildGProps {
    title: string
}
const ChildG: React.FC<ChildGProps> = ({title}) => {
    return <div>ChildG {title}</div>
}
export default ChildG

父組件代碼:

import { useState } from "react"
import ChildF from "./ChildF"
import ChildG from "./ChildG"

const ComE = () => {
    const [updateValue, setUpdateValue] = useState('')
    return <div>
        <ChildF update={(v) => {
            setUpdateValue(v)
        }}></ChildF>
        <ChildG title={updateValue}></ChildG>
    </div>
}
export default ComE

4.任意組件之間的通信

  • 觀察者

如果組件之間沒(méi)有共同的父組件,那我們就可以用觀察者進(jìn)行組件之間的通信丰嘉,這個(gè)時(shí)候我們就需要用到第三方的插件events夯到。下面我們講下如何用events實(shí)現(xiàn)組件間的通信。

首先我們需要執(zhí)行以下命令安裝event

yarn add events

代碼:
安裝成功后饮亏,我們新建一個(gè)event.js文件耍贾,導(dǎo)出一個(gè)全局對(duì)象

import EventEmitter from "events";

export default new EventEmitter()

接收數(shù)據(jù)的組件代碼:

import { useEffect, useState } from "react"
import event from "./class/event"

const ChildI = () => {
    const [message, setMessage] = useState('')
    useEffect(() => {
        //監(jiān)聽(tīng)消息
        event.addListener('message', (message) => {
            setMessage(message)
        })
        return () => {
            event.removeListener('message', (message) => {
                console.log(message)
            })
        }
    })

    return <div>{message}</div>
}

export default ChildI

發(fā)送數(shù)據(jù)的組件代碼:

import event from "./class/event"

const  ChildJ = () => {
    return <div>
        <button onClick={() => {
            //發(fā)送消息
            event.emit('message','這是我發(fā)的消息')
        }}>發(fā)送消息</button>
    </div>
}

export default ChildJ

5.各組件數(shù)據(jù)全局共享

  • window掛載屬性

全局?jǐn)?shù)據(jù)的共享,如果比較簡(jiǎn)單的數(shù)據(jù)路幸,我們可以在window上掛載屬性荐开。但是在typeScript中,因?yàn)?code>Window類中沒(méi)有對(duì)應(yīng)的屬性简肴,所以會(huì)提示報(bào)錯(cuò)晃听,我們可以用以下辦法解決:

src中創(chuàng)建一個(gè)@types文件夾,在@types文件夾下面新建一個(gè)index.d.ts文件,代碼如下:

interface Window {
    customTitle: string
}

有了以上代碼之后就可以在任意地方用以下代碼賦值:

window.customTitle = 'xxx'

取值就用下面代碼:

const customTitle = window.customTitle
console.log(customTitle)
  • 自定義單例

上面的window以及更上面的觀察者其實(shí)都是一個(gè)單例能扒,window掛載屬性雖然方便佣渴,但是違背了設(shè)計(jì)模式的單一原則,而且并不利于代碼管理和維護(hù)赫粥。在開(kāi)發(fā)中,個(gè)人其實(shí)還是建議自定義一個(gè)單例進(jìn)行管理予借。

我們新建一個(gè)class越平,并導(dǎo)出一個(gè)全局對(duì)象

export class Single {
    title?: string
}

export default new Single()

使用時(shí),我們這樣寫(xiě):

import single from './class/Single';
//賦值
single.title = 'abc'

//取值
const title = single.title
console.log(title)

當(dāng)然灵迫,做為一個(gè)習(xí)慣其它強(qiáng)類型語(yǔ)言的程序員秦叛,我們更熟悉這種寫(xiě)法:

export class Single {
    private static instance: Single
    
    public title: string

    private constructor(title: string) {
        this.title = title
    }

    /**
     * 獲取單例對(duì)象
     */
    public static getInstance() {
        if (!this.instance) {
            this.instance = new Single('')
        }
        return this.instance
    }
}

使用時(shí)這樣使用:

//賦值時(shí)這樣寫(xiě)
Single.getInstance().title = 'xxxx'

//取值使用這樣寫(xiě)
const title =  Single.getInstance().title
console.log(title)

原文地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瀑粥,隨后出現(xiàn)的幾起案子挣跋,更是在濱河造成了極大的恐慌,老刑警劉巖狞换,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件避咆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡修噪,警方通過(guò)查閱死者的電腦和手機(jī)查库,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)黄琼,“玉大人樊销,你說(shuō)我怎么就攤上這事≡嗫睿” “怎么了围苫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)撤师。 經(jīng)常有香客問(wèn)我剂府,道長(zhǎng),這世上最難降的妖魔是什么剃盾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任周循,我火速辦了婚禮,結(jié)果婚禮上万俗,老公的妹妹穿的比我還像新娘湾笛。我一直安慰自己,他們只是感情好闰歪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布嚎研。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪临扮。 梳的紋絲不亂的頭發(fā)上论矾,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音杆勇,去河邊找鬼贪壳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蚜退,可吹牛的內(nèi)容都是我干的闰靴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼钻注,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蚂且!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起幅恋,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤杏死,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后捆交,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體淑翼,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年品追,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窒舟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诵盼,死狀恐怖惠豺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情风宁,我是刑警寧澤洁墙,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站戒财,受9級(jí)特大地震影響热监,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饮寞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一孝扛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幽崩,春花似錦苦始、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春咨油,著一層夾襖步出監(jiān)牢的瞬間您炉,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工役电, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赚爵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓法瑟,卻偏偏與公主長(zhǎng)得像冀膝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓢谢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容