Link changing URL but not the page - reactjs

I am using Ant design breadcrumbs. I am trying to change the page using link and pushing the URL, I can see the URL change but the page in not changing.
I tried using Link, then creating a function for onClick but everything just change the URL.
Route:
<Route exact path="/assistant/:wId/skill/xyz/:sid" component={ xyz } />
Tried process 1:
<Breadcrumb separator=">">
<Breadcrumb.Item
onClick={this.redirectToParam2}>
{param2}
</Breadcrumb.Item>
</Breadcrumb>
redirectToParam2 = () => {
this.props.history.push(`/assistant/${wId}/skill/xyz/${sId}`);
}
Tried process 2:
<Breadcrumb separator=">">
<Breadcrumb.Item>
<Link to= {`/assistant/${wId}/skill/xyz/${sId}`}>
{param2}
</Link>
</Breadcrumb.Item>
</Breadcrumb>
Even I tried without the Breadcrumbs component but it's still not changing the page.
I want the page to change as soon as the URL changes.
Thank you in advance.

Try this,
import { Link } from "react-router-dom";
<Breadcrumb separator=">">
<Breadcrumb.Item>
<Link to= {`/assistant/${wId}/skill/xyz/${sId}`}>
{param2}
</Link>
</Breadcrumb.Item>
</Breadcrumb>

The problem you are running into, is that with changing the parameters used as props for the xyz component, the component is not replaced but gets new properties. Since nothing changes, i'm assuming you have state that gets filled either in the constructor or ComponentWillMount/ComponentDidMount.
React class components have a lifecycle function for this: componentDidUpdate.
componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.
Use this as an opportunity to operate on the DOM when the component has been updated. This is also a good place to do network requests as long as you compare the current props to previous props (e.g. a network request may not be necessary if the props have not changed).
Quote from react docs, See: https://reactjs.org/docs/react-component.html#componentdidupdate
componentDidUpdate(prevProps) {
if ((this.props.params.match.sid !== prevProps.params.match.sid) ||
(this.props.params.match.wid !== prevProps.params.match.wid)) {
this.populateState(this.props.params.match); //fill your state
}
}

Related

React Router v6 onclick

I've asked the same question before but now it's not working with react-router v6.
I've simplified the question to how can I output to console when a <Link /> is clicked?
Link in side menu component
<Link to={"/entity"}>Entity</Link>
The route from the main app.js
<Routes>
<Route path="/entity" element={<Entity />} />
</Routes>
How to perform an action once the link is clicked for a second time (the page is already showing) This example is just outputting to console whenever the <Link> is clicked, but the output only shows the first time it loads (or mounts)
function Entity(props) {
console.log('link clicked');
useEffect(() => {
console.log('link clicked');
});
}
The main change from the previous solution to the new one is that RRDv6 doesn't have a Redirect component and the Link component API changed slightly, the route state is now a first-level prop instead of being nested on the to prop object.
Link
<Link
onClick={() => setLinkKey(uuidV4())}
key={linkKey}
to={"/users"}
state={{ key: linkKey }}
>
Users
</Link>
The components rendered on that route still just look for the key to change when clicking that link again if already on the route.
you can use onClicke like a prop in Link :
<Link to={"/entity"} onClick={()=>{
console.log('link clicked');
useEffect(() => {
console.log('link clicked');
});
}}>Entity</Link>

Does react re render everything when we go to a new link?

I am currently creating a react app for practice. I am curious does react render everything when we go to a new link? For eg. These are my routers
<Route exact path="/" component={AuthenticatedUser(Books)}></Route>
<Route exact path="/librarians" component={AuthenticatedUser(Librarians)}></Route>
And my Higher Order Component AuthenticatedUser is as follows:
function AuthenticatedUser(Component) {
return function AuthenticatedComponent({ ...props }) {
const classes = useStyles();
return confirmUserAuthencition() ? (
<>
<SideMenu />
<Header />
<div className={classes.appMain}>
<PageHeader></PageHeader>
<Component {...props}></Component>
</div>
</>
) : (
<Redirect to="/login" />
);
};
}
I am just curious, when I go from "/" link to "/librarians", do components SideMenu and Header rerender?
React re-renders on state change.
From: https://www.educative.io/edpresso/how-to-force-a-react-component-to-re-render
React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.
These changes can come from setState, useState, and/or forceUpdate calls
It depends on the element that redirects you to the new link. If you use react router's <Link to="/librarians"> then no, React will not re-render. However, if you use the standard html <a href="/librarians"> then it will.
No, if you're moving from / to /librarians path, your <SideMenu /> and <Header /> won't re-render. React uses virtual DOM to do the updates on actual DOM (virtual DOM is a copy of the actual DOM and it can do the updates without affecting actual DOM)
During reconcilation process, react compares virtual and actual dom and then do the updates on actual dom based on the nodes that are changed.
In your case, since you're not completely removing AuthenticatedUser component when redirection, it won't re-render <SideMenu /> and <Header /> components that are included in AuthenticatedUser component as childs. But AuthenticatedUser re-render itself since you're changing the passed Component prop.
In order identify this properly you can put a console.log in <SideMenu /> and <Header /> to check whether re-render themselves when moving from / to /librarians.
Since your HOC's return statement depends on the value of the confirmUserAuthencition(), we can't always say whether or not the and components will get re-rendered.
The DOM will stay unaffected as long as the user remains authenticated or unauthenticated. The two components need not be re-rendered each time this route is hit in this case.
React won't re-render the entire page unnecessarily. It will only re-render all components except the SideMenu and Header component.
You may find this article helpful in understanding how react re-renders - Article
It will re-render any component that has changed, as determined by shouldComponentUpdate() for each component
In your case, if you're navigating to the new page via menu navigation, it will re-render the final component, as well as the nav-menu. Depending on your implementation, it's quite likely that the it will re-render the whole AuthenticatedUser component.
Here's the component lifecycle docs:
https://reactjs.org/docs/react-component.html#shouldcomponentupdate

Highlight "antd" menu-item when route is changed from redux-saga

I am using the "antd" framework for a react app and have one slight issues with menus, more precisely with highlighting the currently selected menu item.
I found the following solution that works fine when a link is called, an url is entered directly to a specific page and when "back" is pressed:
render() {
const href = window.location.href.split('/');
const href2 = href[3];
<Menu
mode="horizontal"
theme="dark"
defaultSelectedKeys={['/' + href2]}
selectedKeys={['/' + href2]}
>
<Menu.Item key="/">
...
</Menu.Item>
<Menu.Item key="/test">
...
</Menu.Item>
<Menu>
My problem happens when I set my route from a redux saga (with history.push), I can then see that the "navigation bar" component gets rendered/updated before the "history.push" action is called in the saga.
How can I get my "navigation bar" component to be re-rendered after every route change (however the route change is done). My "navigation bar" is currently a component, because I tried to use the different events, but none of them gets fired. It could also be a functional component (it has no state) it that helps.
I also tried suggestions from "https://stackoverflow.com/questions/41054657/react-routerantd-how-to-highlight-a-menu-item-when-press-back-forward-button" but could not get it to work with my use case
If you're using react-router library you shouldn't use window.location object. In your example of code, you're using the class component. In this case the component in <Route> receives location prop. And you can use it when you want
class Comp extends React.Component {
componentDidUpdate(prevProps) {
// will be true
const locationChanged =
this.props.location !== prevProps.location;
}
}
<Route component={Comp} />;

Route path="/subject/:selectedSubject" does not change subject when navigated via < Link />

I'm trying to display articles filtered by subject. When you access directly path="/subject/:selectedSubject" (subject/TECH) for example it works perfectly. However if you navigate through <Link to={"/subject/TECH"} /> it will change the URL but will not load new articles.
I've tried: connecting everything with "withRouter".
I know that the <Link/> is changing the redux state, however that is not calling componentWillMount() which is where fetchArticles() is.
So, my question is, where should I put fetchArticles in order for it to be called when is triggered. I tried putting it inside render() but it keeps getting called non-stop. Or maybe I'm approaching this the wrong way.
PS: if another path gets called via <Link/>, like for example path="/", it works as intended (loads up new articles).
at App/
<BrowserRouter>
<div>
<Route path="/" exact component={ArticlesList} />
<Route path="/subject/:selectedSubject" component={ArticlesList} />
</div>
</BrowserRouter>
at ArticleList/
componentDidMount() {
if (this.props.match.params.selectedSubject) {
const selectedSubject = this.props.match.params.selectedSubject.toUpperCase();
this.props.fetchArticles(selectedSubject);
} else {
this.props.fetchArticles();
}
}
at Link/
{this.props.subjects.map(subject => {
return (
<Link to={`/subject/${subject.name}`} key={subject.name}>
<li>
<span>{subject.name}</span>
</li>
</Link>
);
})}
Since you use the same Component for / and /subject/:selectedSubject, he's not calling mounting lifecycle methods, including constructor() and componentDidMount().
You have to use updating lifecycle method, especially componentDidUpdate() to handle a update of your component.

Why use Link component in React-Router instead of just anchor tag? [duplicate]

I just started on react router.
I have two questions. What is the difference between using <Link to="/page"> and <a href="page">? Both make the exact same get request to /page but I get an error when I use <a href="page"> but it works when I use <Link to="/page"> when I am nesting routes. I don't understand, how there could be any difference, when I know for fact that both render to exact same url?
Second is the weird arrow function in react router v4 documentation
const About = () => (
<div>
<h2>About</h2>
</div>
)
I know () => {} these are new in ES6 but I cannot find anything on normal brackets instead of parentheses. What are they?
Edit
My index.js class (I have all the imports)
render((
<Router>
<div>
<Route component={App}/>
</div>
</Router>
), document.getElementById('root')
);
My App.js class
class App extends Component {
render() {
return (
<div className="container">
<header>
<span className="icn-logo"><i className="material-icons">code</i></span>
<ul className="main-nav">
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/teachers">Teachers</Link></li>
<li><Link to="/courses">Courses</Link></li>
</ul>
</header>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/teachers" component={Teachers}/>
<Route path="/courses" component={Course}/>
</div>
);
}
}
export default App;
The error I'm getting.
Cannot GET /about on the browser when I try to move to localhost:8080/about. However, when I click the about button, it goes to exactly the same url /about and renders perfectly
This may be a bit late to address your issue and you may well have figured it out. But here's my take:
First:
What is the difference between using <Link to="/page"> and <a
href="page">
On the surface, you seem to be comparing apples and oranges here. The path in your anchor tag is a relative path while that one in the Link is absolute (rightly so, I don't think react-router supports relative paths yet). The problem this creates is say you are on /blah, while clicking on your Link will go to /page, clicking on the <a href='page' /> will take you to /blah/page. This may not be an issue though since you confirmed the correctness of the url, but thought to note.
A bit deeper difference, which is just an addon to #Dennis answer (and the docs he pointed to), is when you are already in a route that matches what the Link points to. Say we are currently on /page and the Link points to /page or even /page/:id, this won't trigger a full page refresh while an <a /> tag naturally will. See issue on Github.
A fix I used to solve my little need around this was to pass in a state property into link like so <Link to={{pathname: "/page", state: "desiredState"}}>Page</Link>. Then I can check for this in the target component's (say <Page />) componentWillReceiveProps like so:
componentWillReceiveProps(nextProps){
if (nextProps.location.state === 'desiredState') {
// do stuffs
}
}
Second question:
the weird arrow function in react router v4 documentation... I cannot find anything on normal brackets instead of parentheses. What are they?
Arrow functions; again #Dennis and #Jaromanda X have kind of addressed it. However, I've got three bits to add:
When you have () => blah without the curly braces {}, you are implicitly returning whatever follows the => in this case blah. But when you have curly braces immediately after the arrow, then it's now your responsibility to return something if you so desire. So () => blah (which by the way is synonymous to () => (blah)) will be more similar to () => { return blah } and not () => { blah }.
So what happens if you want to return an object: { blah: blah }; this is what #Jaromanda X was pointing at. You will then need to do () => ({ blah: blah }) or simply () => ({ blah }) for implicit return or you could return explicitly like so () => { return { blah: blah } }.
My third bit is to point you to MDN
Hope it helps.
The href attribute would trigger a page refresh which would reset the application states. However the link and navlink of react-router doesn't trigger a page refresh. Since React is used to create single page applications most of the time make sure you choose Link or Navlink when working with routing
The component allows you to do more than the normal link element. For instance, because it's a React component you have the benefits of having a state and what not (if you want that). You can see more documentation on here. Without the error I'm not sure what happens, but I suspect the routing library wants you to use the component, over a normal html element.
With regards to () => {} this is a construct which is called an anonymous function, or a lambda expression. It's basically the same as saving a function in a variable: var x = function(){ return (<div>...) }; if you have anything in the first parenthesis, it's a parameter which you have access to: const x = (y) => return y*2; The reason it's done in React is to expose the function scope to the component it lies in.
There is no better then looking at the code source.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/Link.js
You can see that Link is a component, that internally use history. Which is the module|library behind the history and navigation for react-router. And come with different modes (in memory history, browserHistory, hashHistory. And even custom).
Yea as a similarity it render an anchor tag but the default behavior is overridden (preventDefault()). They could have used just a div. But not completely right. As for the reason bellow.
So basically it work like that:
Observe the condition bellow
if (
!event.defaultPrevented && // onClick prevented default
event.button === 0 && // ignore everything but left clicks
(!this.props.target || this.props.target === "_self") && // let browser handle "target=_blank" etc.
!isModifiedEvent(event) // ignore clicks with modifier keys
) {
}
if the condition above is met. It will use history (push or replace). Otherwise it will leave the browser normal behavior. And so in that case it will be just a normal anchor tag <a />. Example letting the browser handle target='blank'. The condition are well explained.
Then depending on the type of history object. The behavior change. Not the behavior of ` itself. But just the result of the history object type.
In resume:
<Link /> is a component, that render a <a /> anchor tag. However in the main conditions the default behavior is prevented (preventDefault()). That allow it to apply the change to the history object (onClick event). Which react-router navigation is based on. And on the some conditions as mentioned above. It just fall back to the browser behavior. And just be exactly a <a /> anchor tag (no preventDefault()).
For the use. If you are using React-router. Then you just need to use Link.

Resources