简体   繁体   English

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

[英]React 16.3 Context API — Provider/Consumer issues

I have been doing some experiment on React 16.3.1 ContextAPI. 我一直在做React 16.3.1 ContextAPI的实验。 and I encountered into something that I couldn't fathom. 我遇到了一些我无法理解的东西。 I was hoping I could use your help. 我希望我可以使用你的帮助。

Note: The problem have been solved but, its not the solution I am looking for. 注意:问题已经解决了,但它不是我想要的解决方案。

Let start with first experiment on multiple components within same file Index.js . 让我们从同一文件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;

As result, this render out perfect without any error. 结果,这完美呈现完美而没有任何错误。 I am able to see name ( Superman ) and age ( 100 ). 我能看到名字( 超人 )和年龄( 100 )。 I am able to increase and decrease age by 1. 我可以将年龄增加和减少1。

As you can see, I have imported {createContext} from react then created {Provider, Consumer} . 如您所见,我已从react创建了{Provider, Consumer} {createContext} ,然后创建了{Provider, Consumer} Wrapped <Provider> with state value and <Consumer> . 使用状态值和<Consumer>包装<Provider> <Consumer>

Next Experiment, was exact copy each component from index.js and paste them separately into their own files. 下一个实验,精确复制index.js中的每个组件,并将它们分别粘贴到自己的文件中。

AppProvider.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 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 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;

As result, I am getting error - TypeError: Cannot read property 'state' of undefined . 结果,我收到错误 - TypeError:无法读取undefined的属性'state'

I am unable to grasp what the exactly error was.. All I did was copy and paste each into files without changing any syntax. 我无法理解确切的错误是什么。我所做的只是复制并粘贴到文件中而不改变任何语法。

Although, Alternative method was to create a new file and add syntax following... 虽然,替代方法是创建一个新文件并添加以下语法...

Context.js Context.js

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

Then go into each files ( AppProvider.js . Person.js and App.js ) and replace... 然后进入每个文件(AppProvider.js。Person.jsApp.js)和替换...

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

...into... ... INTO ...

import Context from './Context.js'; . Also replace... <Provider> into <Context.Provider> and <Consumer> into <Context.Consumer> . 同时将<Provider>替换为<Context.Provider> ,将<Consumer>替换为<Context.Consumer>

And this killed the error. 这就消除了这个错误。 However, this is not the solution I am looking for. 但是,这不是我要找的解决方案。 I wanted to use <Provider> tag instead of <Context.Provider> . 我想使用<Provider>标签而不是<Context.Provider>

Question is, Why am I getting this error? 问题是,为什么我收到此错误?

Why am I unable to use this method... 为什么我无法使用这种方法......

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

for each components in separate files so I could use <Provider> tag ? 对于单独文件中的每个组件,我可以使用<Provider>标签?

Are there any way around to get the solution I'm looking for? 有什么方法可以获得我正在寻找的解决方案吗?

Your help is appreciated and Thanks in advance. 感谢您的帮助,并提前致谢。

Your are getting TypeError: Cannot read property 'state' of undefined. 你得到TypeError:无法读取未定义的属性'state'。 Beacuse every time you call const { Provider, Consumer } = createContext(); 每次调用const { Provider, Consumer } = createContext();都要忘记const { Provider, Consumer } = createContext(); it creates a new object, this object need to be exported in order for consumers to consume this specific object. 它创建一个新对象,需要导出此对象以便消费者使用此特定对象。

So in person.js when you try doing {context.state.age} it really does not have state on this object, you just created a new Context which is empty or rather with React internal methods and properties. 所以在person.js中,当你尝试做{context.state.age}它确实没有关于这个对象的状态,你刚刚创建了一个新的Context,它是空的,或者更确切地说是React的内部方法和属性。

So in order to consume the same object just export it, like you did in Context.js and instead of doing: 因此,为了使用相同的对象,只需导出它,就像在Context.js中那样,而不是执行:

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

replace to: 替换为:

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

Then when you want to use it in other files ( meaning import it ) just call: 然后当你想在其他文件中使用它(意味着导入它)时,只需调用:

import { Consumer, Provider } from './Context.js';

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM