react new context API的一次實踐(補充)

這是一篇我發在掘金上的文章,原文有一個我沒有解決的題目,在網友的解答下我找到了答案,我把文章從新修正編輯后,同步發送到這裏,願望能對人人有所協助。
本文原宣佈於掘金:https://juejin.im/post/5a900d…

近來接到一個簡樸的內部項目,邏輯並不龐雜,就想着不必redux了,用react的new context API碰運氣,折騰了两天,把歷程和感受跟人人分享下。

由因而公司的項目,所以下文的示例代碼都是我從新寫的,望包涵!

基礎用法

起首,讓我們來看一下這個接口的基礎用法:
運用它起首須要運用react的createContext要領建立一個實例:

import React, { createContext } from "react";
const Context = createContext({
  gender: "male"
});;

Context實例供應兩個組件:Provider和Consumer

const ContextProvider = Context.Provider;
const ContextConsumer = Context.Consumer;

个中ContextProvider是數據的宣布方,而ContextConsumer是數據的定閱方。

<ContextProvider value={{ name: "A", age: 18 }}>
    <ContextConsumer>
        {
            context => (
                <div>
                    name:&nbsp;
                    <span>{context.name}</span>
                    &nbsp;age:&nbsp;
                    <span>{context.age}</span>
                </div>
            )
        }
    </ContextConsumer>
</ContextProvider>

ContextProvider作為數據的宣布方,它具有一個名為value的屬性,用於保護數據內容,經由過程value通報給ContextProvider的數據會被宣布出去。
而ContextConsumer作為數據的定閱方,它的props.children是一個函數,吸收的參數是被宣布的數據,我們經由過程挪用這個函數來獵取被ContextProvider宣布的數據,而且返回我們想要襯着的組件。
在這個示例中,我們末了在頁面上能夠显示出name: A age: 18

關於挪用createContext要領時刻的傳參,理論上第一個傳參應該是初始化的數據,然則我運用后發明,假如在ContextProvider的value屬性中不傳入對應的屬性的話,沒法在ContextConsumer中獵取到誰人初始化的屬性。

const Context = createContext({ gender: "male" });
<Context.Provider value={{ name: "A", age: 18 }}>
    <Context.Consumer>
        {
            context => (
                <div>
                    name:&nbsp;
                    <span>{context.name}</span>
                    &nbsp;age:&nbsp;
                    <span>{context.age}</span>
                </div>
            )
        }
    </Context.Consumer>
</Context.Provider>

這個例子中,我一直沒法獵取到gender的值。
我現在還沒找到緣由,假如曉得的朋儕請告訴我一下,感謝!

補充

經由網友的解答和我本身的實驗,這個題目獲得相識答:

  • Provider的value屬性會把初始化Context時通報的初始狀況給覆蓋掉;
  • 假如想要運用初始的狀況,那末就不能運用Provider,也就是說,只要定閱數據而不宣布新數據的情況下,初始的狀況才會有用;

實踐

為了順應項目的需求,我主如果對ContextProvider和ContextConsumer做了封裝。

ContextProvider

因為在我的項目中組件須要定閱而且修正和保護被宣布的數據,所以我須要有一個能夠保護這些數據的處所。因而我建立了一個名為MyProvider的高階組件,並把它放在組件樹的頂層,而各個組件須要定閱的數據就存放在MyProvider的state中,那末我只須要保護它的state就可以保護這些全局的數據了。

export class MyProvider extends React.Component {
  constructor() {
    super();
    this.state = {
      name: "A",
      age: 18
    };
    this.updateContext = this.updateContext.bind(this);
  }
  updateContext(newData) {
    this.setState(Object.assign({}, this.state, newData));
  }
  render() {
    const contextData = { data: this.state };
    Object.defineProperty(contextData, "updateContext", {
      value: this.updateContext
    });
    return (
      <Context.Provider value={contextData}>
        {this.props.children}
      </Context.Provider>
    );
  }
}

MyProvider組件返回的是ContextProvider組件,並把MyProvider的state作為要宣布的數據綁定到了ContextProvider的value屬性上。
前面講過,因為其他組件有要修正被宣布數據的需求,所以我給數據添加了一個不可修正的要領updateContext,這個要領能夠吸收新的數據並更新MyProvider的state,即更新了被宣布的數據。
末了,MyProvider組件將本身的children一成不變的通報給ContextProvider。

ContextConsumer

考慮到ContextConsumer作為定閱方運用比較頻仍,為了輕易其他組件的運用,我將它封裝到高階組件中,並作為函數的返回值運用,以下:

export const MyConsumer = Component => {
  return props => (
    <Context.Consumer>
      {context => {
        return <Component context={context} {...props} />;
      }}
    </Context.Consumer>
  );
};

MyConsumer函數返回一個高階組件。在這個高階組件中,我把ContextConsumer供應的數據加入到Component的props中,如許我只須要在export組件的時刻挪用MyConsumer,而且在組件中運用this.props.context.data就可以獲得被宣布的數據了。以下:

class MyComponent extends React.Component {
  addAge() {
    const { data: { age }, updateContext } = this.props.context;
    const newAge = age + 1;
    updateContext({ age: newAge });
  }
  render() {
    const { name, age } = this.props.context.data;
    return (
      <div>
        name:
        <span>{name}</span>
        age:
        <span>{age}</span>
        <button onClick={() => this.addAge()}>add age</button>
      </div>
    );
  }
}

export default Consumer(MyComponent);

在這個例子中,點擊按鈕,挪用this.props.context.updateContext要領就可以夠經由過程更新MyProvider的state來修正被宣布數據中的age的值。

示例代碼:react-new-context-api-demo

小結

我折騰了两天以後才迴響反映過來,這不就是一個相似於redux的東西嗎?
能夠因為我redux用的多了,關於Prvider和Consumer的封裝下意識的做成了相似redux的用法。再加上運用MyProvider的state作為唯一數據源,又有updateContext這個有點像dispatch的要領來更新數據,乍一看之下,照樣有點redux的影子的。
固然了,我本身寫的完整沒有redux那末好用,也沒有reudx那末嚴謹。所以,厥後我又花了一個上午的時候改用了redux。
然則經由過程此次的實踐,也算是熟習的new context api的用法,對redux也加深了相識吧。
末了,假如你只是想要定閱數據,new context api是個不錯的挑選;然則假如你想要修正和保護被宣布的數據,運用redux會更輕易和平安。

    原文作者:七秋
    原文地址: https://segmentfault.com/a/1190000014942100
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞