【问题标题】:React Context API + withRouter - can we use them together?React Context API + withRouter - 我们可以一起使用它们吗?
【发布时间】:2019-05-27 04:13:00
【问题描述】:

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

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

所以,用户点击导航栏上的按钮。模态打开。 Modal 有一个名为 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 为真,我们将被重定向)...

知道 withRouter 和 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>
        );
    }
}

【问题讨论】:

    标签: reactjs react-router react-context


    【解决方案1】:

    警告来源

    与大多数高阶组件不同,withRouter 将您传递的组件包装在功能组件而不是类组件中。但它仍在调用hoistStatics,它会将您的contextType 静态并将其移动到withRouter 返回的函数组件。这通常应该没问题,但你发现了一个不是这样的实例。您可以查看 repo 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')
       // ..
      }
    
      // ...
    }
    

    【讨论】:

      猜你喜欢
      • 2020-02-08
      • 1970-01-01
      • 2017-05-28
      • 2019-04-28
      • 1970-01-01
      • 2012-04-25
      • 2022-01-04
      • 2012-07-13
      • 1970-01-01
      相关资源
      最近更新 更多