I am building a basic react app in which clicking a button should open a new page in the same tab. I have used React Router for this but that is not working for me.
I want to redirect to a state say, localhost/test , this is my index.js
import Test from './test/Test'
import { Route } from 'react-router-dom';
const myFirstElement = <>
<Button onClick={() => window.location.href='test'}>Click me</Button>
<Route path='test' element={< Test />}></Route>
</>
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(myFirstElement);
My Test.js contains
const Test = <><h1>Hello React!</h1></>
export default Test;
The problem is above code does not render anything on the screen and it doesn't show any error too. But when I remove the
<Route exact path='/test' element={< Test />}></Route>
above code, a button is rendered on the screen, clicking on the button changes the url but doesn't changes state.
Any help will be appreciated.
Issue
When the index.js file includes just a Route component it fails an invariant that checks if the Route component is rendered directly by a Routes or other Route component, and also fails an invariant check for a routing context being provided by a router component. This is why the code runs when you remove <Route path='/test' element={< Test />} />.
The other issue is with using window.location to change the URL. When this happens it reloads the page, which reloads the React app. You should use react-router-dom hooks and components to navigate within the app.
Solution
The app needs to render at least a router and wrap any Route components in the Routes. Use the useNavigate hook to access the navigate function to issue an imperative navigation action to the "/test" path.
Example:
import { BrowserRouter as Router, Routes, Route, useNavigate } from 'react-router-dom';
import Test from './test/Test'
const MyFirstElement = () => {
const navigate = useNavigate();
return (
<>
<Button onClick={() => navigate('test')}>Click me</Button>
<Routes>
<Route path='test' element={<Test />} />
</Routes>
</>
);
}
const root = ReactDOM.createRoot(document.getElementById('root')); root.render(
<Router>
<MyFirstElement />
</Router>
);
If I'm not mistaken, then you definitely need to wrap the application in a BrowserRouter.
import * as React from "react";
import * as ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
{/* The rest of your app goes here */}
<App/>
</BrowserRouter>,
root
);
Routers must be wrapped with Routes
App component:
import React from 'react';
import {Navigate, Route, Routes, useNavigate} from "react-router-dom";
function App() {
return (
<div className={styles.App}>
<Routes>
<Route path="/" element={<Test/>}/>
</Routes>
</div>
);
}
export default App;
import { useState } from 'react';
import About from './Container/About';
import Profile from './Container/Profile';
import {BrowserRouter as Router,Route} from 'react-router-dom'
function App() {
const [state,setState] = useState('Data')
return (
<div >
<button onClick={()=>setState('About')} >About</button>
<button onClick={()=>setState('Profile')}>Profile</button>
{state}
<Router>
<Route element={<About/>} path='/about' />
</Router>
</div>
);
}
export default App;
Why is the browser router is not working as it is showing nothing in the output?
Why is the browser router is not working as it is showing nothing in the output?Why is the browser router is not working as it is showing nothing in the output?Why is the browser router is not working as it is showing nothing in the output?
You need to update the navigation path in order to make this work. Currently you are only updating your state, which is completely decoupled from React Router.
You can either add a link component or naviagate programmatically.
The following should work in your case
import { useNavigate } from "react-router-dom";
[...]
let navigate = useNavigate();
[...]
<button onClick={()=>{ setState('About'); navigate('/about'); } } >About</button>
Or if you don't need the state for anything other than the navigation, you can remove it and replace your buttons with React Router Link components.
The router component maintains it's own state and routing context. You need to either use a Link component or the navigate function to issue an imperative navigation action. Don't forget that all the Route components need to be wrapped by the Routes component so route path matching and rendering functions.
Example:
import About from './Container/About';
import Profile from './Container/Profile';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<div >
<Router>
<Link to='/'>Home</Link>
<Link to='/about'>About</Link>
<Link to='/profile>Profile</Link>
<Routes>
<Route element={<h1>Home</h1>} path='/' />
<Route element={<About />} path='/about' />
<Route element={<Profile />} path='/profile' />
</Routes>
</Router>
</div>
);
}
export default App;
If you decide to use the useNavigate hook to access the navigate function in this App component then the Router will need to be higher in the ReactTree in order for the useNavigate hook and routing components in App to be able to access the routing context.
import { React } from "react";
import { Router as MyRouter, Switch, Route } from "react-router-dom";
import NavBar from "./Components/NavBar";
import Article from "./Components/Article";
import Articles from "./Components/Articles";
var createBrowserHistory = require("history").createBrowserHistory;
const history = createBrowserHistory();
const Router = () => {
return (
<div>
<MyRouter history={history}>
<NavBar />
<Switch>
<Route exact path="/" component={Articles} />
<Route exact path="/home/:title/:id" component={Article} />
</Switch>
</MyRouter>
</div>
);
};
I have a component which display a list of articles, and if you click on one of the articles, you will be redirected to the specifics of that article. Also, article is fetching the content from the server only using the id parameter. I implemented that by using
const history = useHistory();
const onclick = (title, id) =>{
history.push(`/home/${title}/${id}`);
}
Initially, I am having no trouble at all with this structure. However, when I added a random test article, and click on it, the url changes, but the component is never rendered(I tried to log "hello world" in the Article component but it never got printed out). Strangely, if I manually put in the url localhost:3000/home/fijdaifjaid/100 with some random title and the correct id(the id that router fails to render the component for), the component is rendered with no issue, but if I manually put in the correct title it does not work.(My title is "# 1 priority")
Any suggestion on what is the problem here? Also I should note this is not a universal problem, I have several other test ids that are working fine.
My dependencies:
"react": "^17.0.2",
"react-router-dom": "^5.2.0",
Try this
import { React } from "react";
import { Router as MyRouter, Switch, Route } from "react-router-dom";
import NavBar from "./Components/NavBar";
import Article from "./Components/Article";
import Articles from "./Components/Articles";
const Router = () => {
return (
<div>
<MyRouter >
<NavBar />
<Switch>
<Route exact path="/" component={Articles} />
<Route exact path="/home/:title/:id" component={Article} />
</Switch>
</MyRouter>
</div>
);
};
Since you are using Router as a wrapper of your application, what if you don't pass the history object on the Router since you will be using the react hook useHistory().
Instead of router use browser router :
import { React } from "react";
import { BrowserRouter as MyRouter, Switch, Route } from "react-router-dom";
import NavBar from "./Components/NavBar";
import Article from "./Components/Article";
import Articles from "./Components/Articles";
// var createBrowserHistory = require("history").createBrowserHistory;
// const history = createBrowserHistory();
const Router = () => {
return (
<div>
<MyRouter basename={process.env.PUBLIC_URL}>
<NavBar />
<Switch>
<Route exact path="/" component={Articles} />
<Route exact path="/home/:title/:id" component={Article} />
</Switch>
</MyRouter>
</div>
);
};
Before making the build don't forget to add homepage in your package.json :
"homepage": "https://xxxxx.github.io",
React-Router appears to be working in my app except for the fact that I am getting a blank page instead of my component, even though it is directed to the proper path.
I'm scanning the documentation but I can't resolve the issue on my own after looking it over and searching Google/this site.
I had tried...
Making it so that the router.js file just contained the routes only to get the same results. Specifying exact path as well when doing so.
Reinstalling react-router-dom into the component in case there was an error when it downloaded.
Removing the provider in case that was the issue
Placing the code in the router file directly in the App.js file between the provider component tags
These are the files involved.
Router.js
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import LandingPage from '../scenes/LandingPage';
import CityPage from '../scenes/CityPage';
const Router = () => {
return (
<Switch>
<Redirect from='/' to='/landing' />
<Route path='/landing' component={LandingPage} />
<Route path='/citypage' component={CityPage} />
</Switch>
);
}
export default Router;
App.js
import React from "react";
import { BrowserRouter } from "react-router-dom";
import Router from "./services/Router";
import ChosenCityContextProvider from "./services/context/ChosenCityContext";
const App = () => {
return (
<BrowserRouter>
<ChosenCityContextProvider>
<Router />
</ChosenCityContextProvider>
</BrowserRouter>
);
};
export default App;
No error messages accompany the rendering of the site. Aside from the blank page, everything else appears to be working. In the React Dev tools, it states that the Router.Consumer has an object which is revealed to empty when expanded.
What is wrong with my code?
https://codesandbox.io/s/youthful-maxwell-rch1k?fontsize=14
Above is sandbox of code. I have the same issue here
I'm not certain why exactly this fixes the issue, but I've run into this on a work project so knew it worked.
If you add exact into the redirect element it forces the correct behavior.
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import LandingPage from '../scenes/LandingPage';
import CityPage from '../scenes/CityPage';
const Router = () => {
return (
<Switch>
<Redirect exact from='/' to='/landing' />
<Route path='/landing' component={LandingPage} />
<Route path='/citypage' component={CityPage} />
</Switch>
);
}
export default Router;
I tried this and it worked. I'm not sure why before it didn't. If anyone has an explanation please let me know because I am trying to learn what I did wrong initially.
<Route render={() => <Redirect from='/' to='/landing' />} />
I added the above, so my router file looked like this.
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import LandingPage from '../scenes/LandingPage';
import CityPage from '../scenes/CityPage';
const Router = () => {
return (
<Switch>
<Route path='/landing' component={LandingPage} />
<Route path='/citypage' component={CityPage} />
<Route render={() => <Redirect from='/' to='/landing' />} />
</Switch>
);
}
export default Router;
#DLowther has also showed me another solution
import React from "react";
import { Route, Switch, Redirect } from "react-router-dom";
import Page from "./Page";
import Home from "./Home";
const Router = () => {
return (
<Switch>
<Redirect exact from="/" to="/home" />
<Route path="/home" component={Home} />
<Route path="/page" component={Page} />
</Switch>
);
};
export default Router;
I would like to credit this individual for answering my question
I am having trouble changing the view in react with routing. I only want to show a list of users, and clicking on each user should navigate to a details page. Here is the router:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from 'react-router-dom';
import Users from "./components/Users";
import { Router, Route } from "react-router";
import Details from "./components/Details";
ReactDOM.render((
<BrowserRouter>
<div>
<Route path="/" component={Users} />
<Route path="/details" component={Details} />
</div>
</BrowserRouter>
), document.getElementById('app'))
When I use the url /details my browser navigates to that url, but does not change the view. Any other route throws 404 so it seems to recognize the route but not update.
You need to specify the attribute exact for your indexRoute, otherwise for even /details route it will still match with / . Also try to import Route from react-router-dom
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route } from 'react-router-dom';
import Users from "./components/Users";
import Details from "./components/Details";
ReactDOM.render((
<BrowserRouter>
<div>
<Route exact path="/" component={Users} />
<Route path="/details" component={Details} />
</div>
</BrowserRouter>
), document.getElementById('app'))
UPDATE:
Another thing that you need to do is to attach your component Users with withRouter. You need to make use of withRouter only when your component is not receiving the Router props,
This may happen in cases when your component is a nested child of a component rendered by the Router or you haven't passed the Router props to it or when the component is not linked to the Router at all and is rendered as a separate component from the Routes.
In Users.js add
import {withRouter} from 'react-router';
.........
export default withRouter(Users)
DOCS
You just have to wrap the components inside withRouter.
<Route exact path="/mypath" component={withRouter(MyComponent)} />
Here is a sample App.js file:
...
import { BrowserRouter as Router, Route, Switch, withRouter } from "react-router-dom";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route exact path="/" component={withRouter(Home)} />
<Route exact path="/profile" component={withRouter(Profile)} />
</Switch>
</Router>
);
}
}
export default App;
Additional
If you are using react router, componentWillReceiveProps will get called whenever the url changes.
componentWillReceiveProps(nextProps) {
var currentProductId = nextProps.match.params.productId;
var nextProductId = nextProps.match.params.productId; // from the new url
...
}
Note
Alternatively, you may also wrap the component in withRouter before exporting, but then you have to ensure a few other things. I usually skip this step.
export default withRouter(Profile)
I had the same issue and discovered that it was because I had a nested router. Once I removed the nested router, and simply put my component-specific routes within a switch component--the issue was resolved without having to use withRouter or make any additional changes.
<Router> // <--Remove nested Router
<Switch>
<Route exact path="/workflows" component={ViewWorkflows} />
<Route path="/workflows/new" component={NewWorkflow} />
</Switch>
</Router>
Yusufbek is describing a similar issue. I think it's a lot cleaner to store the component related routes at a view level versus storing all of them in one main router. In a production app, that's going to be way too many routes to easily read through and debug issues.
React Router v5 doesn't work with React 18 StrictMode
https://github.com/remix-run/react-router/issues/7870
I have faced the same problem but I fixed it. I have placed the home page as the last. It works for me. Just like below.
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from 'react-router-dom';
import Users from "./components/Users";
import { Router, Route } from "react-router";
import Details from "./components/Details";
ReactDOM.render((
<BrowserRouter>
<div>
<Route path="/details" component={Details} />
<Route path="/" component={Users} />
</div>
</BrowserRouter>
), document.getElementById('app'))
I had a similar issue but with different structure. I've added one Router that will handle all routes, I've used Switch component to switch views. But actually, it didn't. Only URL changed but not view. The reason for this was the Link component used inside of SideBar component which was outside of the Router component. (Yes, I've exported SideBar with "withRouter", not worked).
So, the solution was to move my SideBar component which holds, all Link components into my Router.
The problem is in my linkers, they are outside of my router
<div className="_wrapper">
<SideBar /> // Holds my all linkers
<Router>
<Switch>
<Route path="/" component={Home} />
<Route path="/users" component={Users} />
</Switch>
</Router>
</div>
Solution was moving my linkers into my router
<div className="_wrapper">
<Router>
<SideBar /> // Holds my all linkers
<Switch>
<Route path="/" component={Home} />
<Route path="/users" component={Users} />
</Switch>
</Router>
</div>
I had the same issue with react-router-dom 5
The problem was caused by the history package.
The version I was using was 5.0.0 but they don't work together.
Fixed by downgrading history to 4.10.1
Related issue: https://github.com/ReactTraining/history/issues/804
BrowserRouter fails to maintain history in your case. Use "Router" instead, Usage of this with custom history as props may help resolve your problem.
import {Router, Route, Switch, withRouter } from "react-router-dom";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
import {createBrowserHistory} from 'history';
export const customHistory = createBrowserHistory(); //This maintains custom history
class App extends Component {
render() {
return (
<Router history={customHistory}>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/profile" component={Profile} />
</Switch>
</Router>
);
}
}
export default App;
Then in your components, import customHistory from 'App' and use that to navigate.
customHistory.push('/pathname');
Hope This help! :)
When using Redux and I had similar issues where the url was updating in the address bar but the app was not loading the respective component. I was able to solve by adding withRouter to the export:
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
export default withRouter(connect(mapStateToProps)(MyComponentName))
According to this issue here, react-router-dom isn't compatible with React 18 because BrowserRouter is a child of StrictMode.
So to resolve the issue.
Instead of this:
<React.StrictMode><BrowserRouter>...</BrowserRouter></React.StrictMode>
Do this:
<BrowserRouter><React.StrictMode>...</React.StrictMode></BrowserRouter>
It worked for me this way, I hope it helps.
In my case, I'd mistakenly nested two BrowserRouters.
You need to add exact to the index route and rather than enclosing those Route components by div, use Switch from react-router-dom to switch between the routes.
import React from "react";
import ReactDOM from "react-dom";
import { Route, Switch } from 'react-router-dom';
import Users from "./components/Users";
import Details from "./components/Details";
ReactDOM.render((
<div>
<Switch>
<Route path="/" component={Users} exact/>
<Route path="/details" component={Details} />
</Switch>
</div>
), document.getElementById('app'))
I Tried adding "exact" in front of the home path
like this
<Route exact path="/" component={Home}></Route>
It is working fine...
I had similar issue with React Router version 4:
By clicking <Link /> component, URL would change but views wouldn't.
One of views was using PureComponent rather than Component (imported from react) and that was the cause.
By replacing all route rendered components that were using PureComponent to Component, my issue was resolved.
(Resolution source: https://github.com/ReactTraining/react-router/issues/4975#issuecomment-355393785)
None of the answers here solved my issue, turns out I had to add a dependency to my useEffect hook. I had something like this:
App.js
<Route
path="/product/:id"
component={MyComponent}
/>
MyComponent.jsx
const { id } = useParams();
useEffect(() => {
fetchData();
}, []);
I had a button to change to another product, which would only update the :id on the url, I could see the url changed, but no effect on the page. This change fixed the issue:
MyComponent.jsx
const { id } = useParams();
useEffect(() => {
fetchData();
}, [id]); // add 'id' to dependency array
Now when the id changes, it trigger a function to update the data and works as expected.
Hmm there no any SWITCH to actually switch views.
this is how i use router to switch from landin page to main site
//index.jsx
ReactDOM.render( (<BrowserRouter><App/></BrowserRouter>), document.getElementById('root') );
//App.jsx
render()
{
return <div>
<Switch>
<Route exact path='/' component={Lander}/>
<Route path='/vadatajs' component={Vadatajs}/>
</Switch>
</div>
}
https://jsfiddle.net/Martins_Abilevs/4jko7arp/11/
ups i found you use different router ..sorry then maybe this fiddle be for you useful
https://fiddle.jshell.net/terda12/mana88Lm/
maybe key of solution is hiden in line for main render function ..
Router.run(routes, function(Handler) {
React.render(<Handler />, document.getElementById('container'));
});
I was facing similar issue I resolve to like this please have a look I hope it's working.
You need to use componentWillReceiveProps function in your component.
clicked a link first time by calling url www.example.com/content1/ componentDidMount() is run.
Now when you click another link say www.example.com/content2/ same component is called but this time prop changes and you can access this new prop under componentWillReceiveProps(nextProps) which you can use to call API Or make state blank and get new data.
componentWillReceiveProps(nextProps){
//call your API and update state with new props
}
For me, I had:
export MyClass extends React.Component
with:
export default withRouter(MyClass)
Meanwhile, in my App.js, I had:
import { MyClass } from './MyClass'
Those playing the home game can see my problem. I was not getting the import with the Router passed into the child classes. To clean this up, I moved the withRouter call into the Route component declaration:
<Router exact path={'/myclass'} component={withRouter(MyClass)} />
Back in MyClass, I changed it to a default export:
export default MyClass extends React.Component
And then finally, in App.js, I changed my import to:
import MyClass from './MyClass'
Hopefully this helps someone. This ensures I didn't have two ways to export the same class, thus bypassing the withRouter prepend.
I also had the same problem. Although it is not a very effective solution, I solved it with a cunning method.
The ComponentDidMount method works every time our url changes.
Within the method we can compare the previous url with the current url and we can the state change or page refresh.
componentDidUpdate(prevProps) {
if (this.props.match.url !== prevProps.match.url) {
//this.props.history.go(0) refresh Page
//this.setState(...) or change state
}
}
<Route exact path="/" component={Users} />
<Route exact path="/details" component={Details} />
I was also facing the same issue which was resolved using the exact attribute. try to use the exact attribute.
I met trouble too.
https://github.com/chengjianhua/templated-operating-system
And I have tried the solutions metioned by Shubham Khatri, but It doesn't work.
I solved this problem, maybe can help you.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
According the above guide document, when you use PureComponent or use with state management tools like redux, mobx ... It may block the update of your route. Check your route component, ensure you did't block the rerender od your component.
You should check this out: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
Therefore it's definitely not Users or Details, because they are directly rendered by <Route>, and the location will get passed to props.
I am wondering, why do you need the <div> between <BrowserRouter> and <Route>? Remove that and let me know if it works.
I had a similar issue with a conditional Layout:
class LayoutSwitcher extends Component {
render () {
const isLoggedIn = this.props.isLoggedIn
return (
<React.Fragment>
{ isLoggedIn
? <MainLayout {...this.props} />
: <Login />
}
</React.Fragment>
)
}
}
and rewrote the conditions like so:
render () {
const isLoggedIn = this.props.isLoggedIn
if (isLoggedIn) {
return <MainLayout {...this.props} />
}
return <Login />
}
This solved it. In my case, it seems that the context was lost.
I get the same Issue.
I don't think that in this case he needs to add the prop withRouter,
just check in your NavLink you write the good path name as details.
for the route try to start from the specific route to the general one like
<Route path="/details" component={Details} />
<Route path="/" component={Users} />
in your NavLink it should be something like this
<NavLink className="nav-link" to="/details">
details<span className="sr-only">(current)</span>
</NavLink>
a remarque for the import its better to start by importing all stuff related to React after that import the other module
like this one:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from 'react-router-dom';
import Users from "./components/Users";
import { Router, Route } from "react-router";
import Details from "./components/Details";
come like this:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from 'react-router-dom';
import { Router, Route } from "react-router";
import Users from "./components/Users";
import Details from "./components/Details";
In my case, switching to HashRouter instead of BrowserRouter solved my issue
I was accidentally using a BrowserRouter around my Link's.
<BrowserRouter>
<div>
<Link to="/" component={Users} />
<Link to="/details" component={Details} />
</div>
</BrowserRouter>
If you just started having this issue recently, take a look at https://github.com/remix-run/react-router/issues/7415
The issue is with react-router-dom 5+ and the history dependency.
If you installed it separately using yarn install history you need to uninstall it, do yarn install history#4.10.1
In my case it wasn't working because I imported Browser Router as Router, Like This:
<Router>
<div> <Navbar/></div>
<Routes>
<Route exact path="/" element={<Pageone/>}></Route>
<Route path="/home" element={<Home/>}></Route>
<Route path="/about" element={<About/>}></Route>
<Route path="/contact" element={<Contact/>}></Route>
</Routes>
<div><Footer /></div>
</Router>
</div>
Then It was fixed by adding BrowserRouter instead:
<BrowserRouter>
<div> <Navbar/></div>
<Routes>
<Route exact path="/" element={<Pageone/>}></Route>
<Route path="/home" element={<Home/>}></Route>
<Route path="/about" element={<About/>}></Route>
<Route path="/contact" element={<Contact/>}></Route>
</Routes>
<div><Footer /></div>
</BrowserRouter>
</div>
Hope this helps someone!
Try this,
import React from "react";
import ReactDOM from "react-dom";
import Users from "./components/Users";
import { Router, Route } from "react-router";
import Details from "./components/Details";
ReactDOM.render((
<Router>
<Route path="/" component={Wrapper} >
<IndexRoute component={Users} />
<Route path="/details" component={Details} />
</Route>
</Router>
), document.getElementById('app'))
I had the same issue and I fixed it importing the history from the #types folder in node_modules. I imported it from npm (npm i #history)