In my project, I have to navigate from one component to other without changing the url. For this, I used MemoryRouter
which worked as expected. But now the same idea should work for different routes i.e /one
and /two
. For example,
/one --> BrowserRouter (url change visible)
/
/first
/second
/third
/two --> BrowserRouter (url change visible)
/
/first
/second
/third
For the new visible routes, i.e /one
and /two
, the already established working Memoryroutes (i.e /
, /first
, /second
, /third
) should work properly with respective data as per provided in /one
and /two
.
I am struggling to include the MemoryRoutes inside the BrowserRoutes with the following structure code:
<BrowserRouter>
<Switch>
<Route path="/one" render={() => <MemoryComp configFor="Dave"></MemoryComp>}></Route>
<Route path="/two" render={() => <MemoryComp configFor="Mike"></MemoryComp>}></Route>
</Switch>
</BrowserRouter>
and then the MemoryComp
holds:
<MemoryRouter history={customHistory}>
<Switch>
<Route path="/" render={(props) => <InitPage configFor={this.props.configFor} history={props.history}></InitPage>}></Route>
<Route path="/first" component={FirstPage}></Route>
<Route path="/second" component={SecondPage}></Route>
<Route path="/third" component={ThirdPage}></Route>
</Switch>
</MemoryRouter>
What I am trying to achieve:
history
to achieve the same)Note: This is more likely better to handle the browser routing stuff with server routing instead. Also, this seems can be achieved with any react-stepper plugin. But trying to understand what I am doing wrong here, just for learning purpose.
Here is the whole minimized code, available on Stackblitz (not working):
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import { BrowserRouter, MemoryRouter, Route, Switch } from 'react-router-dom';
import { createBrowserHistory } from "history";
const customHistory = createBrowserHistory();
class MemoryComp extends Component{
render(){
return(
<MemoryRouter history={customHistory}>
<Switch>
<Route path="/" render={(props) => <InitPage configFor={this.props.configFor} history={props.history}></InitPage>}></Route>
<Route path="/first" component={FirstPage}></Route>
<Route path="/second" component={SecondPage}></Route>
<Route path="/third" component={ThirdPage}></Route>
</Switch>
</MemoryRouter>
);
}
}
class InitPage extends Component{
render(){
return (
<>
<ul>
<li onClick={() => this.navigateTo("/")}>Init</li>
<li onClick={() => this.navigateTo("/first")}>First</li>
<li onClick={() => this.navigateTo("/second")}>Second</li>
<li onClick={() => this.navigateTo("/third")}>Third</li>
</ul>
<div>{this.props.configFor}</div>
</>
)
}
navigateTo(path){
this.props.history.push(path, {
data: {
configFor: this.props.configFor
}
})
}
}
class FirstPage extends Component{
constructor(props){
super(props);
this.data = this.props.history.location.state.data;
}
render(){
return (
<>
<ul>
<li onClick={() => this.navigateTo("/")}>Init</li>
<li onClick={() => this.navigateTo("/first")}>First</li>
<li onClick={() => this.navigateTo("/second")}>Second</li>
<li onClick={() => this.navigateTo("/third")}>Third</li>
</ul>
<div>first page</div>
</>
)
}
navigateTo(path){
this.props.history.push(path, {
data: {...this.data, ...{pageName: 'first'}}
})
}
}
class SecondPage extends Component{
constructor(props){
super(props);
this.data = this.props.history.location.state.data;
}
render(){
return (
<>
<ul>
<li onClick={() => this.navigateTo("/")}>Init</li>
<li onClick={() => this.navigateTo("/first")}>First</li>
<li onClick={() => this.navigateTo("/second")}>Second</li>
<li onClick={() => this.navigateTo("/third")}>Third</li>
</ul>
<div>second page</div>
</>
)
}
navigateTo(path){
this.props.history.push(path, {
data: {...this.data, ...{name: 'deducedValue'}}
})
}
}
class ThirdPage extends Component{
constructor(props){
super(props);
this.data = this.props.history.location.state.data;
}
render(){
return (
<>
<ul>
<li onClick={() => this.navigateTo("/")}>Init</li>
<li onClick={() => this.navigateTo("/first")}>First</li>
<li onClick={() => this.navigateTo("/second")}>Second</li>
<li onClick={() => this.navigateTo("/third")}>Third</li>
</ul>
<div>third page</div>
</>
)
}
navigateTo(path){
this.props.history.push(path, {
data: this.data
})
}
}
class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
return (
<div>
<BrowserRouter>
<Switch>
<Route path="/one" render={() => <MemoryComp configFor="Dave"></MemoryComp>}></Route>
<Route path="/two" render={() => <MemoryComp configFor="Mike"></MemoryComp>}></Route>
</Switch>
</BrowserRouter>
</div>
);
}
}
render(<App />, document.getElementById('root'));
The main difference between the two is the way they store the URL and communicate with your web server. A <BrowserRouter> uses regular URL paths.
A <Router> that keeps the history of your “URL” in memory (does not read or write to the address bar). Useful in tests and non-browser environments like React Native.
HashRouter: When we have small client side applications which doesn't need backend we can use HashRouter because when we use hashes in the URL/location bar browser doesn't make a server request. BrowserRouter: When we have big production-ready applications which serve backend, it is recommended to use <BrowserRouter> .
BrowserRouter is usually used in your topmost Parent component. Check this post on medium: medium.com/@pshrmn/… Oh yes, that works!
The <MemoryRouter> solution <MemoryRouter> is a <Router> that keeps the history of your “URL” in memory (does not read or write to the address bar). Useful in tests and non-browser environments like React Native.
BrowserRouter: BrowserRouter is a router implementation that uses the HTML5 history API (pushstate, replacestate, and popstate events) to keep your UI in sync with the URL. It is the parent component used to store all other components. Route: This is a new component introduced in v6 and an upgrade of the component.
To make the screens work with BrowserRouter --> MemoryRouter configuration. To pass data from memory route to another memory route based on the main browser route. ( Trying to use history to achieve the same) Note: This is more likely better to handle the browser routing stuff with server routing instead.
BrowserRouter: BrowserRouter is the router implementation for HTML5 browsers (vs Native) Switch: Switch returns only the first matching route rather than all matching routes. Routes: Route is the conditionally shown component based on matching a path to a URL.
At first I thought there was something wrong with Switch
in combination with MemoryRouter
, but after some debugging I realized it's actually totally independent.
The problem you have is that your base memory route needs to be exact
, otherwise all other routes will match that one and first ('/') will be returned. Just add exact
to your base route.
<MemoryRouter>
<Switch>
<Route exact path="/" render={(props) => <InitPage configFor={this.props.configFor} history={props.history}></InitPage>}></Route>
<Route path="/first" component={FirstPage}></Route>
<Route path="/second" component={SecondPage}></Route>
<Route path="/third" component={ThirdPage}></Route>
</Switch>
</MemoryRouter>
Be careful if you have even more nested routes to always add exact to the root one e.g. /first
needs to be exact in order for this to work correctly:
<Route exact path="/first" component={FirstPage}></Route>
<Route path="/first/nested-1" component={SecondPage}></Route>
<Route path="/first/nested-2" component={ThirdPage}></Route>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With