React 組件之間通訊(數據傳遞)的幾種方式

在咱們使用 React 中,不可避免的要進行組件之間的通訊(數據傳遞)。react

須要注意一點:React中數據的流動是單向的git

組件之間的數據傳遞大體分爲一下幾種:redux

  • 父組件向子組件傳遞數據api

  • 子組件向父組件傳遞數據數組

  • 跨級組件之間傳遞數據(例如父組件向子子組件傳遞數據)bash

  • 非嵌套組件之間傳遞數據app

下面咱們使用兩種方法 (props和context),分別寫段代碼來實現上面四種通訊的方式ide

總體通訊圖解:函數

圖片加載失敗!

運行效果:工具

圖片加載失敗!

使用props通訊

直接上代碼:

import React, { Component } from 'react';

class App extends Component {
    state = { color: 'red' }
    changeColor = color => {
        this.setState({ color: color })
    }
    render() {
        return (
            <div style={{ border: `8px solid ${this.state.color}`, padding: "5px", margin: '5px' }}>
                <h1>Wrapper</h1>
                <Header color={this.state.color}></Header>
                <Main changeColor={this.changeColor.bind(this)} color={this.state.color}></Main>
            </div>
        )
    }
}

class Header extends Component {
    render() {
        return (
            <div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
                <h1>Header</h1>
                <Title color={this.props.color}></Title>
            </div>
        )
    }
}

class Title extends Component {
    render() {
        return (
            <div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
                <h1>Title</h1>
            </div>
        )
    }
}

class Main extends Component {
    render() {
        return (
            <div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
                <h1>Main</h1>
                <Content changeColor={this.props.changeColor} color={this.props.color}></Content>
            </div>
        )
    }
}

class Content extends Component {
    render() {
        return (
            <div style={{ border: `8px solid ${this.props.color}`, padding: "5px", margin: '5px' }}>
                <h1>Content</h1>
                <button onClick={()=>this.props.changeColor("blue")}>變藍</button>
                <button onClick={()=>this.props.changeColor("green")}>變綠</button>
            </div>
        )
    }
}


export default App;
複製代碼

圖解:

圖片加載失敗!

使用context通訊

上面的代碼 想必也看到了不足,若是子子組件須要使用父組件的狀態,就須要逐級傳遞在組件中書寫傳遞代碼

而且這裏面還只是嵌套了兩級,組件也比較少,若是組件多,狀態多的話怎麼辦?
套會套會,就把本身給套迷了,因此使用上面方法很容易出現問題,因此在這裏咱們使用react中給咱們提供的api---Context來解決,也就是執行上下文

固然這也不是最優的解決方式,若是是大型項目的話,最好使用Redux來管理咱們的狀態,若是是小型項目的話,也不必使用Redux,由於React中自身也提供了狀態管理機制

上代碼:

import React, { Component } from 'react';

//利用react中提供的api建立一個上下文
let ColorContext = React.createContext();

// Context對象中提供了兩個api,一個是 Provider 提供數據
// 另外一個是Consumer,  獲取數據

// Context.Provder 是一個組件  Context.Provder就表示提供數據的

// static contextType = ColorContext; 加contextType主要就是用來校驗的,若是不校驗能夠不加

class App extends Component {
    state = { color: 'red' }
    changeColor = color => {
        this.setState({ color: color })
    }
    render() {
        //獲取數據到上下文中
        let contextValue = { color: this.state.color, changeColor: this.changeColor }
        return (
            //使用咱們創造的上下文組件把咱們寫的組件所有包起來,並使用value綁定數據
            <ColorContext.Provider value={contextValue}>
                <div style={{ border: `8px solid ${this.state.color}`, padding: "5px", margin: '5px' }}>
                    <h1>Wrapper</h1>
                    {/* 在這裏咱們就就不須要綁定了 */}
                    <Header></Header>
                    <Main></Main>
                </div>
            </ColorContext.Provider>
        )
    }
}

class Header extends Component {
    // 而後就須要在子組件中使用這個上下文提供的數據了 
    // 須要給類加上一個靜態屬性,值就是這個上下文,哪一個組件使用,那就必須加這個話
    static contextType = ColorContext;
    render() {
        return (
            // 這裏就須要用 this.context 了
            <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
                <h1>Header</h1>
                <Title></Title>
            </div>
        )
    }
}

class Title extends Component {
    static contextType = ColorContext;
    render() {
        return (
            <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
                <h1>Title</h1>
            </div>
        )
    }
}

class Main extends Component {
    static contextType = ColorContext;
    render() {
        return (
            <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
                <h1>Main</h1>
                <Content></Content>
            </div>
        )
    }
}

class Content extends Component {
    static contextType = ColorContext;
    render() {
        return (
            <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
                <h1>Content</h1>
                <button onClick={() => this.context.changeColor("blue")}>變藍</button>
                <button onClick={() => this.context.changeColor("green")}>變綠</button>
            </div>
        )
    }
}


export default App;
複製代碼

圖解:

圖片加載失敗!

上面是在類組件中使用上下文,那麼若是不是類組件,是函數組件呢?該怎麼使用context(上下文)

這裏咱們把Main的類組件換成函數組件:

import React, { Component } from 'react';
let ColorContext = React.createContext();

class App extends Component {
    state = { color: 'red' }
    changeColor = color => {
        this.setState({ color: color })
    }
    render() {
        let contextValue = { color: this.state.color, changeColor: this.changeColor }
        return (
            <ColorContext.Provider value={contextValue}>
                <div style={{ border: `8px solid ${this.state.color}`, padding: "5px", margin: '5px' }}>
                    <h1>Wrapper</h1>
                    <Header></Header>
                    <Main></Main>
                </div>
            </ColorContext.Provider>
        )
    }
}

class Header extends Component {
    static contextType = ColorContext;
    render() {
        return (
            <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
                <h1>Header</h1>
                <Title></Title>
            </div>
        )
    }
}

class Title extends Component {
    static contextType = ColorContext;
    render() {
        return (
            <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
                <h1>Title</h1>
            </div>
        )
    }
}

// class Main extends Component {
//     static contextType = ColorContext;
//     render() {
//         return (
//             <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
//                 <h1>Main</h1>
//                 <Content></Content>
//             </div>
//         )
//     }
// }
function Main() {
    return (
        //須要使用ColorContext.Consumer包起來
        <ColorContext.Consumer>
            {
                value => (
                    <div style={{ border: `8px solid ${value.color}`, padding: "5px", margin: '5px' }}>
                        <h1>Main</h1>
                        <Content></Content>
                    </div>
                )
            }
        </ColorContext.Consumer>
    )
}

class Content extends Component {
    static contextType = ColorContext;
    render() {
        return (
            <div style={{ border: `8px solid ${this.context.color}`, padding: "5px", margin: '5px' }}>
                <h1>Content</h1>
                <button onClick={() => this.context.changeColor("blue")}>變藍</button>
                <button onClick={() => this.context.changeColor("green")}>變綠</button>
            </div>
        )
    }
}


export default App;
複製代碼

事實上,在組件間進行通訊時,這些通訊方式均可以使用,區別只在於使用相應的通訊方式的複雜程度和我的喜愛,選擇最合適的那一個。

固然,本身實現組件間的通訊仍是太難以管理了,所以出現了不少狀態管理工具,如 redux、mobx 等,使用這些工具使得組件間的通訊更容易追蹤和管理。


TAT

相關文章
相關標籤/搜索