React Context API + withRouter - 我们可以一起使用它们吗?
Posted
技术标签:
【中文标题】React Context API + withRouter - 我们可以一起使用它们吗?【英文标题】:React Context API + withRouter - can we use them together? 【发布时间】: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>
);
【问题讨论】:
【参考方案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')
// ..
// ...
【讨论】:
以上是关于React Context API + withRouter - 我们可以一起使用它们吗?的主要内容,如果未能解决你的问题,请参考以下文章
[React] Use the new React Context API
React Context : 从 API 获取数据并在 React 组件中发生某些事件时调用 API