反应路由器和全局上下文

时间:2018-12-05 14:06:04

标签: javascript reactjs react-router

我正在使用React(我的第一个React项目)建立一个电子商务网站,并且正在使用React Router管理我的页面。

我具有以下组件树结构:

<Router>
  <BrowserRouter>
    <Router>
      <withRouter(Base)>
        <Route>
          <Base>
            <BaseProvider>
              <Context.Provider>
                <Header>
                  <PageContent>

基本上是标准的React Router结构,有了Router,我得到了以下内容:

Base.js

import React, { Component } from 'react';
import { withRouter } from 'react-router';

import { Header } from './Header';
import { Footer } from './Footer';
import Provider from '../../BaseProvider';

class Base extends Component {
  render() {
    return (
      <Provider>
        <Header/>
        <div className="container">{this.props.children}</div>
        <Footer />
      </Provider>
    );
  }
}

BaseProvider.js

import React, { Component, createContext } from 'react';

const Context = createContext();
const { Provider, Consumer } = Context;

class BaseProvider extends Component {
  state = {
    cart: [],
    basketTotal: 0,
    priceTotal: 0,
  };

  addProductToCart = product => {
    const cart = { ...this.state.cart };
    cart[product.id] = product;
    this.setState({ cart, basketTotal: Object.keys(cart).length });
  };

  render() {
    return (
      <Provider
        value={{ state: this.state, addProductToCart: this.addProductToCart }}
      >
        {this.props.children}
      </Provider>
    );
  }
}

export { Consumer };
export default BaseProvider;

这从本质上给了我一个模板,因此我只是子页面,而不必每次都包含Header和Footer。

如果我想使用我的全局上下文,则每次都必须导入它,而且好像做错了什么,因为它已经在BaseProvider中导出,因此我肯定可以在任何页面上使用它吗? / p>

如果我要访问关于页面,我将获得相同的组件结构,但是如果不使用以下内容,则无法访问消费者:

import { Consumer } from '../../BaseProvider';

为什么即使每个文件都已导出并且位于BaseProvider的顶层,也必须对每个文件执行此操作?看来这是一个糟糕的模式,我不得不将其导入到大约20个文件中...

不导入它,我得到:

Line 67:  'Consumer' is not defined  no-undef

我尝试仅将contextType添加到base,但是得到:警告:withRouter(Base):功能组件不支持contextType。

Base.contextType = Consumer;

我觉得我刚刚实施了这个错误,因为这种模式肯定可以更好地工作。

1 个答案:

答案 0 :(得分:1)

我建议使用高阶组件-一种将其他组件包装成其他状态或功能的组件。

const CartConsumer = Component => {
  return class extends React.Component {
    render() {
      return (
        <MyContext.Consumer>
          <Component />
        </MyContext.Consumer>
      )
    }
  }
}

然后在要使用它的任何组件中,只需将其包装在export语句中即可:

export default CartConsumer(ComponentWithContext)

这并不能避免完全导入,但比直接使用使用者要少得多。