React Context API + withRouter-我们可以一起使用它们吗?

时间:2018-12-29 22:10:05

标签: reactjs react-router react-context

我构建了一个大型应用程序,其中导航栏上的一个按钮打开了一个模式。

我正在使用上下文API跟踪modalOpen状态。

因此,用户单击导航栏上的按钮。模态打开。模态有一个名为QuoteCalculator的容器。

QuoteCalculator的外观如下:

class QuoteCalculator extends React.Component {
    static contextType = ModalContext;
    // ...

    onSubmit = () => {
        // ...
        this.context.toggleModal();
        this.props.history.push('/quote');
        // ..
    };

    render() {
       //...
       return(<Question {...props} next={this.onSubmit} />;)
    }
}

export default withRouter(QuoteCalculator);

现在,一切正常。当用户提交时,我会走正确的路线。我只是在控制台上看到以下警告

  

index.js:1446警告:withRouter(QuoteCalculator):函数   组件不支持contextType。

我很想忽略该警告,但我认为这不是一个好主意。

我尝试使用重定向。所以像

QuoteCalculator looks as follows:

    class QuoteCalculator extends React.Component {
        static contextType = ModalContext;
        // ...

        onSubmit = () => {
            // ...
            this.context.toggleModal();
            this.setState({done: true});
            // ..
        };

        render() {
           let toDisplay;
           if(this.state.done) {
               toDisplay = <Redirect to="/quote"/>
            } else {
               toDipslay = <Question {...props} next={this.onSubmit} />;
            }
           return(<>{toDisplay}</>)
        }
    }

    export default QuoteCalculator;

这种方法的问题是我一直在获取错误

  

您试图重定向到您当前所在的路线

此外,我宁愿不使用这种方法,因为那样的话,我将不得不撤消已完成的状态(否则,当用户再次单击按钮时,done为true,我们将被重定向)... / p>

您知道Router和history.push怎么回事吗?

这是我的应用

class App extends Component {
    render() {
        return (
            <Layout>
                <Switch>
                    <Route path="/quote" component={Quote} />
                    <Route path="/pricing" component={Pricing} />
                    <Route path="/about" component={About} />
                    <Route path="/faq" component={FAQ} />
                    <Route path="/" exact component={Home} />
                    <Redirect to="/" />
                </Switch>
            </Layout>
        );
    }
}

1 个答案:

答案 0 :(得分:2)

警告来源

与大多数高阶组件不同,withRouter将您传递的组件包装在功能组件而不是类组件中。但是它仍然在调用hoistStatics,这使您的contextType静态并将其移动到withRouter返回的功能组件中。通常,这应该没问题,但是您找到了一个不适合的实例。您可以查看仓库code以获得更多详细信息,但是它很简短,因此我将在此处为您提供相关内容:

function withRouter(Component) {
  // this is a functional component
  const C = props => {
    const { wrappedComponentRef, ...remainingProps } = props;

    return (
      <Route
        children={routeComponentProps => (
          <Component
            {...remainingProps}
            {...routeComponentProps}
            ref={wrappedComponentRef}
          />
        )}
      />
    );
  };

  // ...
  // hoistStatics moves statics from Component to C
  return hoistStatics(C, Component);
}

它确实不应该对任何事物产生负面影响。您的上下文仍然可以使用,并且在withRouter返回的包装组件上将被忽略。但是,为解决该问题而进行更改并不难。

可能的解决方案

最简单

由于模态中所需的全部是history.push,因此您可以将其作为模态的父组件中的道具传递。给定您描述的设置,我想模态包含在应用程序中的某个位置,在组件树中相当高。如果包含模态的组件已经是Route组件,则它可以访问history并可以将push传递给模态。如果不是,则将父组件包装在withRouter中,以访问路由器道具。

还不错

您还可以使模态组件成为模态内容/功能的简单包装,使用ModalContext.Consumer组件将所需的上下文作为道具传递下来,而不是使用contextType

const Modal = () => (
  <ModalContext.Consumer>
    {value => <ModalContent {...value} />}
  </ModalContext.Consumer>
)

class ModalContent extends React.Component {
  onSubmit = () => {
    // ...
    this.props.toggleModal()
    this.props.history.push('/quote')
   // ..
  }

  // ...
}