How to use context api with react router v4?
It looks like that <Switch>
should only have <Route>
and <Redirect >
components as direct children. (source)
I suppose that's why your Redirect
doesn't work as you use ContextB
as a Switch
child.
The simplest but repetitive solution could be to pass your ContextB
as a child of each <Route>
you want:
Note: These solutions suppose that you assigned the default value of your Context component like this:
const MyContext = React.createContext(defaultValue);
<Route exact path='/route2'>
<ContextB.Provider>
<Component1 />
</ContextB.Provider>
</Route>
You can even create a ContextRoute
component for this:
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;
And then use it as a Route:
<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>
With this solution, you then use your context with render props in your nested Components:
return (
<ContextB.Consumer>
{value => <div>{value}</div>}
</ContextB.Consumer>
);
But we can imagine much more solutions to this like HOC, passing context value directly to the route component props, etc...
As a warning to others, accepted answer doesn't really work as you would expect from the original (non-working) concept:
// 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>
In there, /route2
and /route3
are sharing a context and the expectation should be that:
- State is kept between routes transitions.
- If either
Component2
orComponent3
update the context, changes should be reflected back to the other.
None of the above is true for the accepted solution.