iT邦幫忙

2024 iThome 鐵人賽

DAY 15
0
Modern Web

雙向奔赴的websocket與冰冷的react系列 第 15

[day15]React基礎教學(5)父子組件通信

  • 分享至 

  • xImage
  •  

今天要來看React的父子組件間的傳遞囉,前面說到React是單向數據流今天就能看看了

種類介紹

https://ithelp.ithome.com.tw/upload/images/20240923/20162004hymNUcIT0J.png

  • 從A->B/C/D會稱為父子通信
  • 從B->C/D會稱為兄弟通信
  • 從A->E/F/G/H會稱為跨層通信

下面開始個別說明

父子通信

示意圖
https://ithelp.ithome.com.tw/upload/images/20240923/20162004FpnAAchoTK.png

首先我們先來看父子的架構長甚麼樣

function Son() {
    return <div>你乖兒子</div>
  }
function ParentComponent()
  {
      return(
      <>
          <div>
              <label>父子通信(你爹)</label>
              <Son />
          </div>
      </>
      )
  }
export default ParentComponent

當A組件透過<組件名/>導引出的組件變是子,而A則為父

而正常來說兩邊函數是不會互相溝通的,如果函數要溝通一般的函數很直觀function(參數)基本都這樣

但這邊正常應該都不會想到<組件/>怎麼在這裡帶參數吧,下面進行父傳子的操作

  • 父傳子
    1.父組件傳遞數據,子組件標籤身上綁定屬性
    2.子組件接收數據,props參數(props包含了父組件傳遞過來的所有資訊)

父子的溝通大概如下

父
<a組件 參數a={} 參數b={} ... />
子接收
function a組件(props){
    console.log(props.a)
    console.log(props.b)
    ...
}

範例

import React, { useState } from 'react'
function Son(props) {
    return(
    <>
        <label>以下是你乖兒子</label>
        <div>{props.Soncontext},老爹給你的訊息:{props.number}</div>
    </>
    )
}
function ParentComponent()
  {
    const message='老爹的信'
    const [sonvalue, setSonvalue] = useState('')
    return(
    <>
      <div>
          <label>父子通信</label>
          <input type="text" onChange={(e) => setSonvalue(e.target.value)} />
            <br />
          <Son Soncontext={message} number={sonvalue} />
      </div>
    </>
  )
  }
export default ParentComponent

這樣就可以傳遞了,而父傳子能傳遞的東西有甚麼?
他能傳遞的類型很多,例如:數字、字串、布林、字串、字典、函式、jsx都行

    name={string}
    number={123}
    tf={true}
    list={[123,456]}
    dict={[one:1]}
    letter={()=>consolo.log(123)}
    jsx={<span>test</span>}

但是,子組件是不能修改父組件的值ex:props.number = 0

  • props.children
    這個是父傳子時的默認屬性用法如下
將上面的Son替換
function Son(props) {
    return(
    <>
        <label>以下是你乖兒子</label>
        <div>{props.Soncontext},老爹給你的訊息:{props.number}</div>
        {props.children}
        {props.children[0]}
    </>
    )
}
父呼叫子的地方替換
<Son Soncontext={message} number={sonvalue}>
<label>來旅遊的</label>
<label>來旅遊的2</label>
</Son>

props.children能夠一次將包裹住的元素渲染出來,也可透過[n]一一渲染出來

  • 子傳父
    採用的方法為透過父的函數來傳遞子的訊息,當傳遞函數時建議on開頭

一樣先上code在解說

import React, { useState } from 'react'
function Son(props) {
    const [sonMsg, setSonMsg] = useState('');
    return (
        <div>
            <button onClick={() => props.onGetSonMsg(sonMsg)}>
                傳送子組件訊息
            </button>
            <input type='text' onChange={(e)=>setSonMsg(e.target.value)}/>
        </div>
    );
}

function ParentComponent() {
    const [msg, setMsg] = useState('');
    const getMsg = (msg) => {
        console.log(msg);
        setMsg(msg); 
    };
    return (
        <div>
            <label>父子通信 - 子傳父</label>
            <br />
            <label>等待子消息:{msg}</label>
            <Son onGetSonMsg={getMsg} />
        </div>
    );
}
export default ParentComponent;

我們在父組件中,透過 <Son onGetSonMsg={getMsg} /> 的方式,將一個回調函數 getMsg 傳遞給子組件,這樣子組件在執行某個動作時(例如點擊按鈕),可以通過這個回調函數將資料傳回父組件。

接下來,子組件通過 props.onGetSonMsg(sonMsg) 來調用這個回調函數,也就是從父組件傳遞下來的 getMsg 函數。sonMsg 作為參數傳遞給父組件的 getMsg,這樣父組件就可以接收到子組件發送的數據,並在父組件中進行相應的處理(例如更新狀態)。

兄弟通信

由於React的單向數據流,所以方式十之八九就是如下啦
https://ithelp.ithome.com.tw/upload/images/20240923/20162004MfKnQvloN9.png

範例

import React, { useState } from 'react'

function A({ onGetName }) {
    const name = 'A msg'
    return (
        <div>
            this is A
            <button onClick={() => onGetName(name)}>send</button>
        </div>
    )
}

function B({name}) {
    return (
        <div>
            this is B,get:{name}
        </div>
    )
}
function ParentComponent() {
    const getname = (name) => {
        console.log(name)
        setName(name)
    }
    const [name, setName] = useState('')
    return (
        <>
            <div>
                <header>
                    <a href="/">Home</a>
                    <label>子傳父</label>
                </header>
                <A onGetName={getname}></A>
                <B name={name}></B>
            </div>
        </>
    )
}

export default ParentComponent;

就是用回調函數的方式,先將子傳給父,父做處理再用useState去重新渲染B,就是用上面得父傳子+子傳父的結合

  • 解構語法
    你可以發現我的function B的參數改成用{name}這就是解構語法

這樣就不用前面再加個props甚麼的,但缺點就是數量一多就很麻煩,所以斟酌使用

跨層通信

你可能會想該不會父傳子做兩次吧,那也是可以,但也可以直接丟給你孫子唷(使用Context API)。
https://ithelp.ithome.com.tw/upload/images/20240923/20162004KHrx3194V7.png
步驟:
1.使用creatContext創建一個上下文對象的Ctx
2.在頂層組件(父)中通過Ctx.Provoid組件提供數據
3.在底層組件(孫子)中通過useContext函數鉤子函數獲取消費數據
註:可一次申請多個Ctx

import { createContext, useContext } from "react"
const MsgCtx = createContext()
function A() {
    return (
        <div>
            this is A
            <B />
        </div>
    )
}

function B() {
    const msg = useContext(MsgCtx)
    return (
        <div>
            this is B,{msg}
        </div>
    )
}
function ParentComponent() {
    const msg = 'send material'
    return (
        <>
            <div>
                <header>
                    <a href="/">這裡是父</a>
                </header>
                <MsgCtx.Provider value={msg}>
                    這邊還是父
                    <A />
                </MsgCtx.Provider>
            </div>
        </>
    )
}

export default ParentComponent;
  • 使用 createContext() 函數來創建一個上下文對象 MsgCtx。這個上下文會提供一個共享的數據源,所有在 MsgCtx.Provider 包裹範圍內的組件都可以訪問這個共享數據。

  • 在 ParentComponent(父) 中,我們創建了一個變量 msg,其值為 'send material',並且使用 MsgCtx.Provider 將這個變量作為上下文提供給子組件和孫子組件。

  • MsgCtx.Provider:Provider 是 Context API 中用來傳遞數據的組件,這裡的 value={msg} 表示將 msg 的數據傳遞給 Provider 包裹範圍內的組件。

  • 子組件 A 被 Provider 包裹,雖然 A 本身沒有使用 useContext,但它的子組件 B 能夠通過 useContext 存取 msg。

  • 在 B 組件中,我們使用 useContext(MsgCtx) 來獲取 MsgCtx.Provider 提供的數據。

結束啦

今天就到這囉,這就是React的單向數據流所造成的通信架構,這大概就是我最長的文章了,休息啦


上一篇
[day14]React基礎教學(4)useEffect
下一篇
[day16]React基礎教學(6)自定義hook與組件
系列文
雙向奔赴的websocket與冰冷的react30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言