events事件在React中做跨級通信

最近使用 React Hook 寫項(xiàng)目的新需求,遇到一個(gè)問題就是跨級組件的通信,項(xiàng)目中的組件狀態(tài)沒有用 Redux 來管理狀態(tài),跨級組件通信是通過 React context 來做,如果是 class 組件,可以直接使用 this.context... ,但是現(xiàn)在用 React Hook 來編寫函數(shù)組件,讓組件內(nèi)部有自己的狀態(tài),但是函數(shù)組件是沒有 this 概念的,所以不能用 context 來做,于是想到了 Node.js 中的 events 來實(shí)現(xiàn)。

本來想通過安裝 npm 包里面的 events 來做,然后看到如下這句話

You usually do not have to install events yourself! If your code runs in Node.js, events is built in. If your code runs in the browser, bundlers like browserify or webpack also include the events module.

意思是通過 webpack 打包構(gòu)建的項(xiàng)目,無需單獨(dú)安裝events模塊, webpack 構(gòu)建時(shí)直接包含了 events模塊,所以就直接使用吧。

events 通過發(fā)布訂閱自定義事件來實(shí)現(xiàn)消息的傳播,項(xiàng)目根組件內(nèi)部嵌套很深的子組件在獲取接口請求的時(shí)候,需要將 loaddig 的狀態(tài)傳給根組件,根組件來控制 loadding 動畫的顯示和隱藏,根組件結(jié)構(gòu)如下:

export default class MainFrame extends React.Component{
render(){
        return(
            <Spin style={{height:'100%'}} spinning={!!this.state.requestCount}>
                <Layout style={{height:'100%',width:'100%'}}>
                    <MyHeader user={this.state.userInfo}/>
                    <div className="page-content-warpper table-4-ie9">
                        <Layout className="table-row-4-ie9">
                            <Sider className="table-cell-4-ie9" width={200}>
                                <LeftMenu 
                                      mySelect={this.props.menuselect} 
                                      menu={this.props.menu} 
                                      classNmae="page-left-menu"/>
                            </Sider>
                            <Layout className="table-cell-4-ie9" style={{ padding: '10px 20px' }}>
                                <Content>
                                    {this.props.children}
                                </Content>
                            </Layout>
                        </Layout>
                    </div>
                </Layout>
            </Spin>
        )
    }
}

右邊的子組件就在 this.props.children 中顯示,Spinspinning 就是做全局的 loadding 動畫加載效果,嵌套組件為了傳遞狀態(tài)給根組件,就需要根組件在掛載之后聲明自定義事件,嵌套組件去訂閱事件,然后通過觸發(fā)自定義事件將狀態(tài)傳遞給根組件。

新建一個(gè) events.js 文件,代碼如下:

// events.js
import EventEmitter from 'events';
class PPEmitter extends EventEmitter {};

export default new PPEmitter();

根組件注冊自定義事件,根組件為MainFrame.js

// MainFrame.js
import PPEmitter from './event';

export default class MainFrame extends React.Component{
    constructor(props){
        super(props);
        this.state={
            requestCount:0,
        }
    }
    changeRequestCount = (count)=>{
        //這里加定時(shí)是為了保證state.requestCount是最新狀態(tài)
        setTimeout(()=>{
            let requestCount = this.state.requestCount+count;
            requestCount = requestCount<0?0:requestCount;
            this.setState({requestCount})
        })
    }
    componentDidMount(){
        // 聲明自定義事件
        this.eventEmitter = PPEmitter.addListener('changeRequestCount', (msg) => {
            this.changeRequestCount(msg);
        })
    }
    componentWillUnmount(){
        // 卸載時(shí)移除事件
        PPEmitter.removeListener(this.eventEmitter);
    }
    render(){
        return(
            <Spin style={{height:'100%'}} spinning={!!this.state.requestCount}>
                <Layout style={{height:'100%',width:'100%'}}>
                    <MyHeader user={this.state.userInfo}/>
                    <div className="page-content-warpper table-4-ie9">
                        <Layout className="table-row-4-ie9">
                            <Sider className="table-cell-4-ie9" width={200}>
                                <LeftMenu mySelect={this.props.menuselect} menu={this.props.menu} classNmae="page-left-menu"/>
                            </Sider>
                            <Layout className="table-cell-4-ie9" style={{ padding: '10px 20px' }}>
                                <Content>
                                    {this.props.children}
                                </Content>
                            </Layout>
                        </Layout>
                    </div>
                </Layout>
            </Spin>
        )
    }
}

MainFrame 組件在componentDidMount中注冊自定義事件changeRequestCount,卸載時(shí)在componentWillUnMount中移除事件監(jiān)聽。
嵌套組件 Domain 的代碼如下:

//Domain.js
import PPEmitter from './event'

const Domain = (props) => {
  //數(shù)據(jù)請求
  const getData = () => {
     // 發(fā)起請求顯示 loadding
     PPEmitter.emit('changeRequestCount', 1);
     setTimeout(() => {
        // 數(shù)據(jù)返回之后,隱藏loadding
        // 觸發(fā)自定義事件
       PPEmitter.emit('changeRequestCount', -1);
     }, 1000)
  }
}
export default Domain;

效果如下:


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容