React Context

Context 提供了一個無需為每層組件手動添加 props,就能在組件樹間進(jìn)行數(shù)據(jù)傳遞的方法。

在一個典型的 React 應(yīng)用中,數(shù)據(jù)是通過 props 屬性自上而下(由父及子)進(jìn)行傳遞的,但這種做法對于某些類型的屬性而言是極其繁瑣的(例如:地區(qū)偏好,UI 主題),這些屬性是應(yīng)用程序中許多組件都需要的。Context 提供了一種在組件之間共享此類值的方式,而不必顯式地通過組件樹的逐層傳遞 props。

Context的使用場景

Context 是為了在一個組件樹內(nèi)部共享"全局"的數(shù)據(jù)而設(shè)計的, 因此當(dāng)涉及一些全局可能需要獲取的數(shù)據(jù)可以考慮使用Context, 例如: 當(dāng)前用戶的認(rèn)證、頁面屬性、首先語言等等.

使用之前的考慮

  1. 謹(jǐn)慎使用Context, 因為這會使得組件之間的復(fù)用性變差.
  2. 如何避免組件間props的層層傳遞問題?

API

React.createContext
  • 創(chuàng)建一個 Context 對象。當(dāng) React 渲染一個訂閱了這個 Context 對象的組件,這個組件會從組件樹中離自身最近的那個匹配的 Provider 中讀取到當(dāng)前的 context 值。
  • 只有當(dāng)組件所處的樹中沒有匹配到 Provider 時,其 defaultValue 參數(shù)才會生效。這有助于在不使用 Provider 包裝組件的情況下對組件進(jìn)行測試。注意:將 undefined 傳遞給 Provider 的 value 時,消費(fèi)組件的 defaultValue 不會生效。
  • */context/index.ts
    import React from 'react';
    import IAppContext from './IAppContext';
    import Initializer from './initializer';
    
    //    const MyContext = React.createContext(defaultValue);
    const AppContext = React.createContext<IAppContext>(Initializer.default);
    
    export default AppContext;
    
  • */context/IAppContext.ts
    export default interface IAppContext {
      lan: string;
      userId: number;
      hotelId: number | string;
      isInternalUser: boolean;
      dyffs: KeyValuePairs<boolean>;
      [key: string]: any;
    }
    
  • */context/initializer.ts
    import IAppContext from './IAppContext';
    
    export default {
        default: {
            hotelId: 0,
            isInternalUser: false,
            lan: 'en-us',
            userId: 0,
            dyffs: {}
        },
    
        init(): IAppContext {
            // @ts-ignore
            const ga = global.EPC && global.EPC.Logging && global.EPC.Logging.GA;
            const { href } = window.location;
            const isDev = href.search('localhost.expediapartnercentral.com') !== -1;
    
            return {
                hotelId: (ga && ga.resourceId) || this.default.hotelId,
                isInternalUser: (ga && ga.isInternalUser) || this.default.isInternalUser,
                lan: (ga && ga.locale) || this.default.lan,
                dyffs: window.EPC && window.EPC.DYFFs || {},
                userId: (ga && ga.userId) || this.default.userId,
            };
        },
    };
    
Context.Provider
Context.Consumer
Class.contextType
Context.displayName

獲取Context的方法?

  1. 使用 Content 提供的 Consumer 組件
  2. 使用 useContext
    useContext 函數(shù)是 React Hooks 三大基礎(chǔ) hooks函數(shù)之一.
    import React from 'react';
    import AppContext from '../../common/context';
    
    //  獲取Context的值;
    const context = React.useContext(AppContext);
    

Examples

Attentions

1. 重復(fù)渲染問題
  • 因為 context 會使用參考標(biāo)識(reference identity)來決定何時進(jìn)行渲染,這里可能會有一些陷阱,當(dāng) provider 的父組件進(jìn)行重渲染時,可能會在 consumers 組件中觸發(fā)意外的渲染。舉個例子,當(dāng)每一次 Provider 重渲染時,以下的代碼會重渲染所有下面的 consumers 組件,因為 value 屬性總是被賦值為新的對象:
class App extends React.Component {
    render() {
        return (
            <MyContext.Provider value={{something: 'something'}}>
                <Toolbar />
            </MyContext.Provider>
        );
    }
}
  • 為了防止這種情況,將 value 狀態(tài)提升到父節(jié)點的 state 里:
class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
           value: {something: 'something'},
        };
    }

    render() {
        return (
            <Provider value={this.state.value}>
                <Toolbar />
            </Provider>
        );
    }
}
2. 不依賴 ReactDOM
  • React Context 并不依賴于 ReactDOM 的 render, 也不需要放在根節(jié)點上, 它可以放在任何節(jié)點.
  • 同時, 只要保證在Provider的子孫節(jié)點里面, 就可以使用 React.useContext() 或者 Context 提供的Consumer組件去取Context對象的內(nèi)容.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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