如何在React中处理多个上下文?

时间:2019-08-31 19:09:52

标签: javascript reactjs

React的新手-我试图在我的App组件中使用多个上下文,我尝试遵循multiple contexts上的官方指南。

这是我当前的代码:

App.js

import React from "react";
import { render } from "react-dom";
import Login from "./Login";
import AuthContext from "./AuthContext";
import LayoutContext from "./LayoutContext";
import LoadingScreen from "./LoadingScreen";

class App extends React.Component {
  render() {
    const { auth, layout } = this.props;

    return (
      <LayoutContext.Provider value={layout}>
        <LoadingScreen />
        <AuthContext.Provider value={auth}>
          <AuthContext.Consumer>
            {auth => (auth.logged_in ? console.log("logged in") : <Login />)}
          </AuthContext.Consumer>
        </AuthContext.Provider>
      </LayoutContext.Provider>
    );
  }
}

render(<App />, document.getElementById("root"));

Login.js

import React from "react";

class Login extends React.Component {
  render() {
    return (
      <div></div>
    );
  }
}

export default Login;

AuthContext.js

import React from "react";

const AuthContext = React.createContext({
  logged_in: false
});

export default AuthContext;

LayoutContext.js

import React from "react";

const LayoutContext = React.createContext({
  show_loading: false
});

export default LayoutContext;

LoadingScreen.js

import React from "react";
import LayoutContext from "./LayoutContext";

class LoadingScreen extends React.Component {
  render() {
    return (
      <LayoutContext.Consumer>
        {layout =>
          layout.show_loading ? (
            <div id="loading">
              <div id="loading-center">
                <div className="sk-chasing-dots">
                  <div className="sk-child sk-dot1"></div>
                  <div className="sk-child sk-dot2"></div>
                </div>
              </div>
            </div>
          ) : null
        }
      </LayoutContext.Consumer>
    );
  }
}

export default LoadingScreen;

在此示例之后,我从未真正理解this.props(在App.js中)如何容纳我的不同上下文。

authlayout都显示为未定义,this.props为空,这又会导致我的应用抛出诸如Cannot read property 'show_loading' of undefined

的错误

我立即喜欢React文档中提供的示例,但是我无法使它正常工作。

1 个答案:

答案 0 :(得分:3)

我已经制作了一个小片段,向您展示如何构建上下文提供者和使用者。

在这种情况下,我的App组件是应用程序的根目录。它具有所有提供程序,以及每个提供程序的价值。我没有更改此值,但我愿意。

然后它只有一个子组件MyOutsideComponent,其中包含所有链接的使用者。有更好的方法可以做到这一点,我只是想向您逐一展示链式消费者的工作方式。在实践中,您可以使用一些技巧来巧妙地减少这种情况。

MyOutsideComponent具有实际的组成部分MyComponent,它接收所有上下文元素并将其值放在页面上。没什么好说的,重点是要说明如何传递值。

let FirstContext = React.createContext('first');

let SecondContext = React.createContext('second');

let ThirdContext = React.createContext('third');

let FourthContext = React.createContext('fourth');

let MyComponent = (props) => {
  return (<span >{Object.values(props).join(" ")}</span>);
};

let App = (props) => {
  return (
  <FirstContext.Provider value="this is">
    <SecondContext.Provider value="how you">
      <ThirdContext.Provider value="pass context">
        <FourthContext.Provider value="around">
          <MyOutsideComponent />
        </FourthContext.Provider>
      </ThirdContext.Provider>
    </SecondContext.Provider>
  </FirstContext.Provider>
  );
};

let MyOutsideComponent = () => {
    return ( < FirstContext.Consumer >
          {first =>
            (< SecondContext.Consumer >
             {second =>
               (< ThirdContext.Consumer >
                 {third =>
                   (<FourthContext.Consumer >
                     {fourth =>
                      (<MyComponent first={first} second={second} third={third} fourth={fourth} />)
                     }
                   </FourthContext.Consumer>)
                 }
               </ThirdContext.Consumer>)
             }
           </SecondContext.Consumer>)
         }
       </FirstContext.Consumer>);
   }
   
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

现在,进行实际说明。 createContext为您提供两个实际组成部分:ProviderConsumer。如您所见,此Provider具有价值。 Consumer将带有一个参数(即您的上下文值)的单个函数作为子元素。

这是文档不太清楚的地方,希望我能对您有所帮助。 除非Provider是组件的直接父级,否则它不会自动在props中传递。你必须自己做。因此,在上面的示例中,我链接了四个消费者,然后将它们全部排列在组件的道具中。

您已经问过基于类的组件,这就是它最终的样子:

let FirstContext = React.createContext('first');

let SecondContext = React.createContext('second');

let ThirdContext = React.createContext('third');

let FourthContext = React.createContext('fourth');

class MyComponent extends React.Component {
  render() {
    return ( < span > {Object.values(this.props).join(" ")} < /span>);
  }
}

class App extends React.Component {
  render() {
    return (
      <FirstContext.Provider value = "this is" >
        <SecondContext.Provider value = "how you" >
          <ThirdContext.Provider value = "pass context" >
            <FourthContext.Provider value = "around" >
              <MyOutsideComponent / >
            </FourthContext.Provider>
          </ThirdContext.Provider >
        </SecondContext.Provider>
      </FirstContext.Provider >
    );
  }
}

class MyOutsideComponent extends React.Component {
  render() {
    return (
      <FirstContext.Consumer >
        { first => 
          (< SecondContext.Consumer >
            { second =>
              ( < ThirdContext.Consumer >
                {  third =>
                  ( < FourthContext.Consumer >
                    { fourth =>
                      ( < MyComponent first = {first} second={second} third={third} fourth={fourth} />)
                    }
                  </FourthContext.Consumer>)
                }
              </ThirdContext.Consumer>)
            }
          </SecondContext.Consumer>)
        }
      </FirstContext.Consumer>
    );
  }
}
ReactDOM.render( < App / > , document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app" />