• <dd id="by9vk"><pre id="by9vk"></pre></dd>
  • <dd id="by9vk"></dd>
    <progress id="by9vk"><pre id="by9vk"></pre></progress><tbody id="by9vk"></tbody>
    <tbody id="by9vk"></tbody>

    <rp id="by9vk"><ruby id="by9vk"></ruby></rp>

    好程序員-千鋒教育旗下高端IT職業教育品牌

    400-811-9990
    我的賬戶
    好程序員

    專注高端IT職業培訓

    親愛的猿猿,歡迎!

    已有賬號,請

    如尚未注冊?

    [HTML5] 好程序員web前端分享Context-React跨組件訪問數據的利器

    [復制鏈接]
    94 0
    葉子老師 發表于 5 天前 | 只看該作者 |閱讀模式 打印 上一主題 下一主題
      好程序員web前端培訓分享Context-React跨組件訪問數據的利器  Context提供了一種跨組件訪問數據的方法。它無需在組件樹間逐層傳遞屬性,也可以方便的訪問其他組件的數據  在經典的React應用中,數據是父組件通過props向子組件傳遞的。但是在某些特定場合,有些數據需要在各個組件之間共享。Context為我們提供一種組件之間共享數據的方式,可以避免數據在組件樹上逐層傳遞  使用Context的場合
    Context可以在組件樹的組件之間共享“全局”數據。例如:登陸的用戶信息,用戶選擇的主題、語言等等。下面的例子中,我們“手動”自上而下傳遞theme屬性,用來設定Button的樣式。
    class App extends React.Component {
      render() {
        return <Toolbar theme="dark"></Toolbar>;
      }
    }
    function Toolbar(props) {
      // The Toolbar component must take an extra "theme" prop
      // and pass it to the ThemedButton. This can become painful
      // if every single button in the app needs to know the theme
      // because it would have to be passed through all components.
      return (
        <div>
          <ThemedButton theme={props.theme}></ThemedButton>
        </div>
      );
    }
    class ThemedButton extends React.Component {
      render() {
        return <Button theme={this.props.theme}></Button>;
      }
    }
    使用Context,我們可以避免通過多個中間組件傳遞props
    // Context lets us pass a value deep into the component tree// without explicitly threading it through every component.// Create a context for the current theme (with "light" as the default).const ThemeContext = React.createContext('light');
    class App extends React.Component {
      render() {
        // Use a Provider to pass the current theme to the tree below.
        // Any component can read it, no matter how deep it is.
        // In this example, we're passing "dark" as the current value.
        return (
          <ThemeContext.Provider value="dark">
            <Toolbar></Toolbar>
          </ThemeContext.Provider>
        );
      }
    }
    // A component in the middle doesn't have to
    // pass the theme down explicitly anymore.
    function Toolbar(props) {
      return (
        <div>
          <ThemedButton />
        </div>
      );
    }
    class ThemedButton extends React.Component {
      // Assign a contextType to read the current theme context.
      // React will find the closest theme Provider above and use its value.
      // In this example, the current theme is "dark".
      static contextType = ThemeContext;
      render() {
        return <Button theme={this.context} />;
      }
    }
    有時候,有些數據需要被很多組件訪問,而且這些組件在組件樹的不同層上。Context可以使我們以“廣播”的形式,在各個組件中共享數據的改變
    Context相關APIReact.createContext
    const MyContext = React.createContext(defaultValue);復制代碼
    創建一個新的Context對象。當React渲染一個組件,且該組件注冊了Context時,它將讀取父組件中,距離該組件最近的Provider組件的Context
    defaultValue只有“Consumer”組件找不到Provider組件時,才會被使用。
    Context.Provider
    <MyContext.Provider value={/* some value */}>復制代碼
    每個Context對象都攜帶一個名叫Provider的React組件。Provider可以使得“Consumer”組件監聽context的變更
    通過向Provider的后代Consumer組件傳遞value的prop,一個Provider可以與多個Consumer組件建立聯系。
    所有的后代Consumer組件在Provider的value屬性更新后,都會被重新渲染。這個更新從Provider到其后代Consumer組件之間傳播,但是并不會觸發shouldComponentUpdate方法。所以即使Consumer組件的祖先組件沒有更新,Consumer組件也會更新
    Context使用與Object.is相同的算法來對比value的新、舊值,以判定其value是否被更新了
    注意
    當向value傳遞對象時,這種判定value是否改變的方式可能會引起問題。
    Class.contextType
    class MyClass extends React.Component {
      componentDidMount() {
        let value = this.context;
        /* perform a side-effect at mount using the value of MyContext */
      }
      componentDidUpdate() {
        let value = this.context;
        /* ... */
      }
      componentWillUnmount() {
        let value = this.context;
        /* ... */
      }
      render() {
        let value = this.context;
        /* render something based on the value of MyContext */
      }
    }
    MyClass.contextType = MyContext;
    class的contextTpe屬性賦值一個Context對象后,我們可以通過this.context在組件的各個聲明周期函數中獲取到當前的Context對象的方法
    注意:
    通過這種方式,每個組件只能注冊一個context對象。如果需要讀取多個context的value值
    如果編碼中使用了ES實驗中的語法,那么可以使用類的靜態(static)成員來初始化contextTYpe.代碼如下:
    class MyClass extends React.Component {
    static contextType = MyContext;
    render() {
       let value = this.context;
       /* render something based on the value */
    }
    }
    Context.Consumer
    <MyContext.Consumer>
      {value => /* render something based on the context value */}
    </MyContext.Consumer>
    Consumer是一個監聽context變化的React組件。它使得我們可以在一個函數組件中,監聽contxt的改變。
    Consumer組件要求其子元素為一個函數。該函數的參數接收當前的context的value值,要求返回一個React節點(node) 傳遞給該函數的參數value等于距離此Consumner最近的外層Provider組件的context值。如果沒有外層的Provider組件,則等于調用createContext()時傳遞的參數值(context的默認值)。
    注意
    更多關于“子元素為一個函數”的信息
    栗子在嵌套組件中更新Context
    開發中,我們經常需要在某些嵌套結構很深的組件上更新context的value值。此時,我們可以向下傳遞一個函數,用它來更新context的value。代碼如下:
    theme-context.js
    // Make sure the shape of the default value passed to// createContext matches the shape that the consumers expect!export const ThemeContext = React.createContext({
      theme: themes.dark,
      toggleTheme: () => {},
    });
    theme-toggler-button.js
    import {ThemeContext} from './theme-context';
    function ThemeTogglerButton() {
      // The Theme Toggler Button receives not only the theme
      // but also a toggleTheme function from the context
      return (
        <ThemeContext.Consumer>
          {({theme, toggleTheme}) => (
            <button
              onClick={toggleTheme}
              style={{backgroundColor: theme.background}}>
              Toggle Theme
            </button>
          )}
        </ThemeContext.Consumer>
      );
    }
    export default ThemeTogglerButton;
    app.js
    import {ThemeContext, themes} from './theme-context';import ThemeTogglerButton from './theme-toggler-button';
    class App extends React.Component {
      constructor(props) {
        super(props);
        this.toggleTheme = () => {
          this.setState(state => ({
            theme:
              state.theme === themes.dark
                ? themes.light
                : themes.dark,
          }));
        };
        // State also contains the updater function so it will
        // be passed down into the context provider
        this.state = {
          theme: themes.light,
          toggleTheme: this.toggleTheme,
        };
      }
      render() {
        // The entire state is passed to the provider
        return (
          <ThemeContext.Provider value={this.state}>
            <Content />
          </ThemeContext.Provider>
        );
      }
    }
    function Content() {
      return (
        <div>
          <ThemeTogglerButton />
        </div>
      );
    }
    ReactDOM.render(<App />, document.root);
    使用多個Contexts
    為了保持React的快速渲染,我們需要將每個consumer組件編寫成一個獨立的組件節點(node)
    // Theme context, default to light themeconst ThemeContext = React.createContext('light');
    // Signed-in user contextconst UserContext = React.createContext({
      name: 'Guest',
    });
    class App extends React.Component {
      render() {
        const {signedInUser, theme} = this.props;
        // App component that provides initial context values
        return (
          <ThemeContext.Provider value={theme}>
            <UserContext.Provider value={signedInUser}>
              <Layout />
            </UserContext.Provider>
          </ThemeContext.Provider>
        );
      }
    }
    function Layout() {
      return (
        <div>
          <Sidebar />
          <Content />
        </div>
      );
    }
    // A component may consume multiple contexts
    function Content() {
      return (
        <ThemeContext.Consumer>
          {theme => (
            <UserContext.Consumer>
              {user => (
                <ProfilePage user={user} theme={theme} />
              )}
            </UserContext.Consumer>
          )}
        </ThemeContext.Consumer>
      );
    }
    如果有兩個以上的context經常一起使用,我們需要考慮創建一個render prop component一并提供兩個Context
    注意
    因為context使用引用標示符(reference identity)來判斷何時需要重新渲染,所以有些情況下,當provider的父元素重新渲染時,會觸發consumer的非內部渲染。例如下面代碼,在每次Provider重新渲染時,會重新渲染所有的consumer組件。因為會一直創建一個新的對象賦值給value(value一直在變)
    class App extends React.Component {
      render() {
        return (
          <Provider value={{something: 'something'}}>
            <Toolbar />
          </Provider>
        );
      }
    }
    為了避免這個問題,可以將value放在組件的state中
    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          value: {something: 'something'},
        };
      }
      render() {
        return (
          <Provider value={this.state.value}>
            <Toolbar />
          </Provider>
        );
      }
    }
    好程序員web前端培訓官網;http://www.jyf24.com/html5_class.shtml

    精彩內容,一鍵分享給更多人!
    收藏
    收藏0
    轉播
    轉播
    分享
    淘帖0
    支持
    支持0
    反對
    反對0
    回復

    使用道具 舉報

    您需要登錄后才可以回帖

    本版積分規則

    關注我們
    好程序員
    千鋒好程序員

    北京校區(總部):北京市海淀區寶盛北里西區28號中關村智誠科創大廈

    深圳西部硅谷校區:深圳市寶安區寶安大道5010號深圳西部硅谷B座A區605-619

    杭州龍馳智慧谷校區:浙江省杭州市下沙經濟技術開發區元成路199號龍馳智慧谷B座7層

    鄭州校區:鄭州市二七區航海中路60號海為科技園C區10層、12層

    Copyright 2007-2019 北京千鋒互聯科技有限公司 .All Right

    京ICP備12003911號-5 京公安網11010802011455號

    請您保持通訊暢通1對1咨詢馬上開啟

    Pictoa