如何在React Router V4中使用上下文API?

vin*_*dim 9 reactjs react-router

我正在尝试在我的应用程序上使用React 16.3中的新上下文API进行一些测试,但我不明白为什么我的重定向永远无法工作。

<ContextA>
  <Switch>
    <Route exact path='/route1' component={ Component1 } />
    <ContextB>
      <Route exact path='/route2' component={ Component2 } />
      <Route exact path='/route3' component={ Component3 } />
    </ContextB>
    <Redirect from='/' to='/route1' />
  </Switch>
</ContextA>
Run Code Online (Sandbox Code Playgroud)

我不想让我的ContextB可用于所有路由,仅2和3。我该怎么做?

Nen*_*enu 15

看起来<Switch>应该只具有<Route><Redirect >组件作为直接子代。(来源

我想这就是为什么你的Redirect,你使用不工作ContextBSwitch孩子。

最简单但重复的解决方案可能是让您ContextB成为每个<Route>想要的孩子的孩子:

注意:这些解决方案假定您为Context组件分配了默认值,如下所示: const MyContext = React.createContext(defaultValue);

<Route exact path='/route2'>
  <ContextB.Provider>
    <Component1 />
  </ContextB.Provider>
</Route>
Run Code Online (Sandbox Code Playgroud)

您甚至可以ContextRoute为此创建一个组件:

import React from 'react';
import { Route } from 'react-router-dom';

const ContextRoute = ({ contextComponent, component, ...rest }) => {
  const { Provider } = contextComponent;
  const Component = component;

  return (
    <Route {...rest}>
      <Provider>
        <Component />
      </Provider>
    </Route>
  );
};

export default ContextRoute;
Run Code Online (Sandbox Code Playgroud)

然后将其用作路线:

<ContextA>
  <Switch>
    <Route exact path='/route1' component={ Component1 } />
    <ContextRoute exact path='/route2' contextComponent={ContextB} component={ Component2 } />
    <ContextRoute exact path='/route3' contextComponent={ContextB} component={ Component3 } />
    <Redirect from='/' to='/route1' />
  </Switch>
</ContextA>
Run Code Online (Sandbox Code Playgroud)

使用此解决方案,然后将上下文与嵌套组件中的渲染道具一起使用:

return (
  <ContextB.Consumer>
    {value => <div>{value}</div>}
  </ContextB.Consumer>
);
Run Code Online (Sandbox Code Playgroud)

但是我们可以想像更多的解决方案,例如HOC,将上下文值直接传递给路由组件prop等。

  • 似乎上下文 B 的状态将丢失,但是如果您从 /route2 或 /route3 转到 /route1。似乎通常将根放在某个地方然后在需要它的那些组件中抓取它通常会更好? (9认同)

Nic*_*one 15

作为对其他人警告,接受的答案并不像您对原始(非工作)概念所期望的那样有效:

// This comes from the original question (doesn't work as-is!)
<ContextA>
  <Switch>
    <Route exact path='/route1' component={ Component1 } />
      <ContextB>
        <Route exact path='/route2' component={ Component2 } />
        <Route exact path='/route3' component={ Component3 } />
      </ContextB>
      <Redirect from='/' to='/route1' />
   </Switch>
</ContextA>
Run Code Online (Sandbox Code Playgroud)

在那里,/route2并且/route3正在共享上下文,并且期望应该是:

  1. 状态保持在路由转换之间。
  2. 如果Component2Component3更新上下文,则更改应反映回另一个。

对于已接受的解决方案,上述情况均不成立。

  • 你说得对,收获不错。即使您的答案实际上不是一个*(也许在已接受的答案中进行评论或编辑会更合适?)*。使其工作的一种方法是将 ContextB 提供程序提升到 Switch 组件之上,并在路线 2 和 3 上使用消费者。我有时间时会尝试更新答案 (10认同)
  • 我仍在寻找解决方案,但尚未弄清楚。@Nenu 我对你关于提升上下文提供者的理论感兴趣 - 你解决过这个问题吗? (2认同)

小智 8

在路由中使用渲染方法。这将解决您的问题,就像我在我的应用程序中所做的那样。

<Route
  path="/"
  render={(props) => (
    <ContextB>
      <Component2 {...props} />
    </ContextB>
  )}
/>
Run Code Online (Sandbox Code Playgroud)