URL with ID not handled by React Router - reactjs

I'm using React Router v4 in my ReactJs app and looks like whenever I have a path with an ID in it, React Router is not handling it because I see the page refreshing and I'm losing all the data in my Redux store in the process.
Here's my routes section:
<Switch>
<Route exact path="/member" component={Home} />
<Route exact path="/member/accounts" component={Accounts} />
<Route path="/member/projects/profile/:id" component={ProjectProfile} />
</Switch>
Here's how I'm generating the link. This is the link when the user clicks, I see a refresh on my browser.
import { Link } from 'react-router-dom';
... omitted for brevity
const profileUrl = "/member/projects/profile/" + project.id;
<Link to={profileUrl}>Click here</Link>
Other links defined in my routes work fine e.g. home and accounts.
What am I doing wrong here?

Do you pass onClick event handler to the Link component?
If so make sure everything is fine with the handler. You can try to remove it temporarily, in order to debug the refreshing.
Credits:
https://stackoverflow.com/a/46115304/4312466
https://github.com/ReactTraining/react-router/pull/4066#issuecomment-383910759

After a lot of testing, I found the cause. We must use NavLink or Link from react-router-dom whenever linking to a component.
I noticed I wasn't consistent in using NavLink in my app. Instead I was using regular
<a href={myModuleUrl}>Module Name</a>.
Once I switched to using NavLink, it worked as intended.

Related

What is the correct way to setup an independent Route that is not a part of App.js in React Router Dom?

I'm trying to create an independent Route (not sure if that's the correct term) at BulletinBoard.js where I can use Link to go to Create Bulletin component.
I'm also trying to create another independent Route at BulletinList.js where I can navigate to Edit Bulletin with their respective IDs.
Before this, I tried using useRouteMatch with path and url, but apparently that wasn't the correct way to do it, now I'm told to use useLocation, it does adds the /createbulletin and /editbulletin/id paths behind the current URL, but it doesn't navigate to the component itself.
I've been cracking my head over this for the past 2 days and I still haven't figured out the correct way to do this.
Here is the codesandbox that I've created for reference.
The reason your code didnt navigate to a different component after the url changed is because you didnt use the exact attribute when declaring the route. So its matching /bulletinboard/anything and then it always renders de BulletinBoard component.
You could define all routes at the App.js file like
<Switch>
<Route path="/" component={Home} exact />
<Route path="/bulletinboard" component={BulletinBoard} exact />
<Route path="/bulletinboard/edit/:id" component={EditBulletinBoard} exact />
<Route path="/infohub" component={InfoHub} exact />
<Route component={NotFound} />
</Switch>
Also, check out the useHistory hook
So at the BulletinBoard.js when the user clicks the link
onClick={() => history.push(`/bulletinboard/edit/${id}`)}
Note that the edit route renders a different component that your codesandbox didn't have yet

React Router ignores my PrivateRoute wrapper when navigating using a Link

I'm having a strange issue with React Router. My PrivateRoute wrapper doesn't do its thing when navigating using a Link or NavLink.
Essentially I have something like this:
<BrowserRouter>
<Switch>
<Route exact path="/"><Home /></Route>
<PrivateRoute exact path="/private"><Private /></PrivateRoute>
</Switch>
</BrowserRouter>
PrivateRoute is just a wrapper around Route that checks for authentication.
Now, if I go to /private by typing it in the address bar, PrivateRoute does its job (and redirects to /login, but that doesn't matter).
However, if I use a NavLink in the Home component which has to="/private", React Router routes to the private route even if the user is unauthenticated.
Is there any way I can resolve this reasonably? And why does React Router behave like this and doesn't "go through" all the routes in BrowserRouter each time you navigate using a NavLink?
To solve your problem, you need to add exact or exact="true" on public Route.
If you don't include exact="true", <Route path="/"> refers all sub routes starting with /.
So /private will match / route hence it will render <Home /> component.
Here is updated code
<BrowserRouter>
<Switch>
<Route path="/" exact>
<Home />
</Route>
<PrivateRoute path="/private">
<Private />
</PrivateRoute>
</Switch>
</BrowserRouter>
Here is sample code
Well, this was a quite simple and dumb fix actually.
The problem was that the PrivateRoute component didn't "remount" when changing routes using Links (that is interesting and somehow clever behavior of React Router, I can imagine this improves performance).
Meanwhile, typing a URL into the address bar refreshes the entire page, thus "remounting" all components.
Since the logic for checking auth was in componentDidMount only, it didn't launch if the component wasn't "remounted", therefore creating my issue.
For any possible future visitors, to fix this problem, just move your auth checking logic from componentDidMount somewhere else, and reference it both in componentDidMount and componentDidUpdate. Don't forget to check if props actually changed in componentDidUpdate — otherwise you'll create an infinite loop — like so:
componentDidUpdate(prevProps, prevState) {
// You could also use shallowCompare, but that wasn't needed in my case
if (this.props.requiredPerms !== prevProps.requiredPerms) {
this.checkAuth(); // method with the logic which was in componentDidMount before
}
}

How to use React HashRouter for route parameters?

I have two routes, a base path and a customer route. The customer route takes a customerId parameter.
<HashRouter>
<Switch>
<Route path="/mapper/:mappingId/" exact component={Mapper}/>
<Route path="/" exact component={App} />
</Switch>
</HashRouter>
then in the react component I am calling it like this to navigate
window.open(`/customer/${customerId}`)
(updated, still doesn't work)
but when I navigate it just goes to the App component. I have to use HashRouter because the react app is wrapped in Electron. BrowserRouter works on the web
The url i get when i navigate is this:
http://localhost:3000/customer/ca023754-bb75-4f64-a19c-958525b53e12#/
I also tried adding backslash in Route, /customer/:customerId/, that didn't work as well
I have read How to use React Router with Electron? but it doesn't really work
I finally figured this out. Hashrouter expect the url to have "#/" after the basepath. so it should be window.open('#/customer/${customerId}')

Include static HTML folder/files in create-react-app

I'm using create-react-app with the react-router-dom module for my React app. I have a subfolder containing static HTML/CSS/JS that I'd like the react app to render. It could be as simple as having the router show /static/index.html.
I've searched around and there doesn't seem to be a definitive answer as to how to so this using create-react-app. Any advice is appreciated.
In order to use routing in your react app, you have to do the following:
Setup
Install react by opening the terminal/cmd, going to the current apps directory, and type in the following command: npm i react-router-dom. Hit enter and let it install.
Next, go to the index.js file, and import BrowserRouter, by adding the following line at the beginning of your code: import { BrowserRouter } from 'react-router-dom'
Then change your render thing to look like this:
ReactDOM.render(
,
document.getElementById('root')
);
What that does, is it basically tells react that App will have routing support.
Now go to your app.jsx file and import the following: import { Route, Switch } from 'react-router-dom';. (I'll explain what they all are later on.)
Now that the behind-the-scenes is setup, we can start adding routes, or paths, to out app.
Apply Routes
Go to your app.jsx file and at the render part instead of just
having components there, let's make a route. (A route just means a
url path.)
You can have components that are always there, no matter what the url path is. In order to do that, just don't have those items as routes. See the example below for more clarification.
To create a route just add the following code: <Route path="/myPath" component={myComponent} />
myComponent will display when the user goes to www.myWebsite.com/myPath.
The problem with this, is say you have a route to /myPath, and a route to / (the home page, i.e. www.myWebsite.com/), then when the user navigates to www.myWebsite.com/myPath, the home page will also display. To prevent that from happening, just wrapp all the routes in a <Switch></Switch> component.
So the final code in the render part of app.jsx will look is like this:
return (
<div className="App">
<div className="bg" />
// Will always show `Header` no matter what the rout is.
<Header/>
<Switch>
<Route path="/about" component={about} />
<Route path="/" exact component={WelcomContent} />
</Switch>
// Will always show `Footer` no matter what the rout is.
<Footer />
</div>
);
Hope this helps. Let me know if you have anymore questions.

React router 4 - Why is my component only rendered on manually setting the url but not on clicking a Link with same url?

I started using react router v4 and I have 2 questions. Ive been researching and reading about router 4 but cant explain why the following happens:
ps. I have included only code I thought is relevant, please let me know if I should dd more.
<BrowserRouter>
<div>
<Route path="/" component={PostsIndex} />
<Route path="/posts/new" component={PostsNew}></Route>
</div>
</BrowserRouter>
PostsIndex:
<Link to="/posts/new">Add a Post</Link>
1. What happens with my code below is on route '/' I am being shown PostsNew Component. When I manually put url to '/posts/new' both components are being rendered - PostsIndex and PostsNew which is intended. HOWEVER, when im on '/' and click on my Link (with path: /posts/new) nothing happens. The PostsNew component is not being rendered unless I refresh the page (so the url already changed after I click the link but I need to refresh it-url stays same- and only then will the nested component being rendered). Why does this happen?
Another question:
Below I want to achieve the opposite- NOT nesting routes. When I use switch and put the most specific route first, it works. Also when I click on the Link, the PostsNew is being rendered without the need to refresh. My question is just to understand routing better:
I would expect in my code below, both components being rendered on /posts/new - but here the PostsNew component is NEVER being rendered. Why?
Why is my Link working when I use Switch and if I dont I must manually refresh/put url? Thanks!
If you only want a specific path to render you need to add an exact attribute to the Routes:
<Route exact path="/" component={PostsIndex} />
<Route exact path="/posts/new" component={PostsNew}/>

Resources