React 16.3 Context API - 提供者/消费者问题

时间:2018-04-07 15:14:00

标签: javascript reactjs

我一直在对React 16.3.1 ContextAPI做一些实验。我遇到了一些我无法理解的东西。我希望我可以帮助你。

注意:问题已经解决但是,它不是我想要的解决方案。

首先在同一个文件 Index.js 中对多个组件进行首次实验。

import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();

class AppProvider extends Component {
  state = {
    name: 'Superman',
    age: 100
  };

  render() {
    const increaseAge = () => {
      this.setState({ age: this.state.age + 1 });
    };

    const decreaseAge = () => {
      this.setState({ age: this.state.age - 1 });
    };
    return (
      <Provider
        value={{
          state: this.state,
          increaseAge,
          decreaseAge
        }}
      >
        {this.props.children}
      </Provider>
    );
  }
}

class Person extends Component {
  render() {
    return (
      <div className="person">
        <Consumer>
          {context => (
            <div>
              <p>I'm {context.state.name}</p>
              <p>I'm {context.state.age}</p>
              <button onClick={context.increaseAge}>
                <span>+</span>
              </button>
              <button onClick={context.decreaseAge}>
                <span>-</span>
              </button>
            </div>
          )}
        </Consumer>
      </div>
    );
  }
}

class App extends Component {
  render() {
      return (
        <AppProvider>
          <div className="App">
            <p>Imma Apps</p>
            <Person />
          </div>
        </AppProvider>
      );
    }
  }

export default App;

结果,这个渲染完美而没有任何错误。我能看到名字(超人)和年龄( 100 )。我能够将年龄增加和减少1.

如您所见,我已从反应中导入{createContext},然后创建{Provider, Consumer}。使用州值和<Provider>包裹<Consumer>

下一个实验,精确复制 index.js 中的每个组件,并将它们分别粘贴到自己的文件中。

AppProvider.js

import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();

class AppProvider extends Component {
  state = {
    name: 'Superman',
    age: 100
  };

  render() {
    const increaseAge = () => {
      this.setState({ age: this.state.age + 1 });
    };

    const decreaseAge = () => {
      this.setState({ age: this.state.age - 1 });
    };
    return (
      <Provider
        value={{
          state: this.state,
          increaseAge,
          decreaseAge
        }}
      >
        {this.props.children}
      </Provider>
    );
  }
}
export default AppProvider;

Person.js

import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();

class Person extends Component {
  render() {
    return (
      <div className="person">
        <Consumer>
          {context => (
            <div>
              <p>I'm {context.state.name}</p>
              <p>I'm {context.state.age}</p>
              <button onClick={context.increaseAge}>
                <span>+</span>
              </button>
              <button onClick={context.decreaseAge}>
                <span>-</span>
              </button>
            </div>
          )}
        </Consumer>
      </div>
    );
  }
}
export default Person;

App.js

import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();

class App extends Component {
  render() {
      return (
        <AppProvider>
          <div className="App">
            <p>Imma Apps</p>
            <Person />
          </div>
        </AppProvider>
      );
    }
  }

export default App;

结果,我收到错误 - TypeError:无法读取未定义的属性'state'

我无法理解确切的错误是什么。我所做的只是将每个文件复制并粘贴到文件中而不更改任何语法。

虽然,替代方法是创建一个新文件并添加语法......

Context.js

import { createContext } from 'react';
const Context = createContext();
export default Context;

然后进入每个文件( AppProvider.js Person.js App.js )并替换...

import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();

... INTO ...

import Context from './Context.js';。同时将<Provider>替换为<Context.Provider>,将<Consumer>替换为<Context.Consumer>

这就杀了这个错误。但是,这不是我要找的解决方案。我想使用<Provider>代码而不是<Context.Provider>

问题是,为什么我收到此错误?

为什么我无法使用此方法...

import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();

对于单独文件中的每个组件,我可以使用<Provider>标记吗?

有什么方法可以获得我正在寻找的解决方案吗?

感谢您的帮助,并提前致谢。

1 个答案:

答案 0 :(得分:4)

您的 TypeError:无法读取未定义的属性“状态”。 因为每次调用const { Provider, Consumer } = createContext();它都会创建一个新对象时,需要导出此对象,以便消费者使用此特定对象。

所以在person.js 当你尝试做{context.state.age}时,它确实没有这个对象的状态,你刚刚创建了一个新的Context,它是空的,或者更确切地说是React的内部方法和属性。

所以为了消费,同样的对象只需导出它,就像你在Context.js中那样,而不是做:

import { createContext } from 'react';
const Context = createContext();
export default Context;

替换为:

import { createContext } from 'react';
const { Provider, Consumer } = createContext();
export { Consumer, Provider };

然后当你想在其他文件中使用它(意味着导入它)时,只需调用:

import { Consumer, Provider } from './Context.js';
相关问题