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

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

Related

Why is nextjs persistent layout re-rendering all the time?

I am trying to follow the persistent layout examples as presented on the official docs and Adam Wathan's article here.
This is what I know so far:
I am aware about React's reconciliation process. I know that if react realizes the virtual dom tree of a component hasn't changed, then it wont update the html dom elements of that tree/component. Article I used to better understand some of these concepts
React rerenders a component if its state changes. If a prop changes, it should not? Or is there an assumption that a prop is implicitly considered a state?
If a parent re-renders, then children will be re-rendered.
I am aware (though still need to learn/readup) on React.memo. Once I do, I plan to utilize that as well. I am vaguely aware that it caches the component for the given input (props) and if props doesn't change, it returns the cached component.
Based on the above, I would say that persistent layout works because the layout used in _app.js is provided the page as its prop (children). Since layout's own state doesn't change, layout shouldn't get re-rendered. However, that is not what I am noticing, and hence this long winded question.
Just so I am clear, when i say re-render, I am talking about React recreating the virtual dom for the component rather than repainting the html dom. My issues are with the former and not the later.
What I am seeing is that every time I click on the "Profile" link (even if I am already on the same page):
The entire layout (including top nav bar, icons, search bar and links) all re-render.
I see the console log messages being printed for each of them.
I used the "Profiler" tool and it too shows me all the components rerendering.
I thought that a persistent layout meant that it wouldn't be re-evaluated all the time? The printing of console logs indicates that the component is being re-evaluated every time. I know React.memo would avoid this entirely, but then what exactly is "persistence" about this? What am i missing or failing to understand about persistent layouts in this case?
What I have looks like this:
/pages/profile.js (and similarly /pages/anotherPage.js)
function sampleProfilePage (props) = {
return (
<div>I am on profile page</div>
);
}
export default sampleProfilePage
_app.js
function MyApp({Component, pageProps}) {
return (
<SimpleLayout>
<Component {...pageProps} />
<SimpleLayout />
);
}
SimpleLayout.js
function SimpleLayout ({children}) {
return (
<>
{console.log("simpleLayout re-rendered")}
<SimpleTopBar />
<main>{children}</main>
</>
);
}
export default SimpleLayout;
SimpleTopbar.js NOTE: css can be ignored. Its present in .module.css file.
function SimpleTopBar () {
return (
<div className={classes.container}>
{console.log("SimpleTopBar re-rendered")}
<Link href="/profile">Profile</Link>
<IconCircle />
<SearchBar />
<IconSquare />
<Link href="/anotherPage">Another Page</Link>
</div>
);
}
export default SimpleTopBar;
IconCircle (and similarly IconSquare) NOTE: ignore css again. Also, I recently became aware that defaultProps are deprecated. I am in the process of updating/writing inline default values.
export function IconCircle (props) {
return (
<svg xmlns="http://www.w3.org/2000/svg"
className={props.name}
... rest of svg data ...
</svg>
);
}
IconCircle.defaultProps = {
name: classes.iconCircle
}
SearchBar.js NOTE: this is taken straight from Adam's code in order to try and compare what I was seeing.
function SearchBar (props) {
return (
<div className="mt-2">
{console.log("Search bar rendered")}
<input className="block w-full border border-gray-300 rounded-lg bg-gray-100 px-3 py-2 leading-tight focus:outline-none focus:border-gray-600 focus:bg-white"
placeholder="Search..."
/>
</div>
);
}
export default SearchBar;
Disclaimers:
I am a backend engineer and just starting to learn React and Nextjs. Its is highly possible that my design and understanding is limited or not exactly what one might expect in the industry/professionally. So, if there are some general practices or commonly known knowledge, please do not assume that I am following that or aware of it. Its part of the reason why I pasted entire functions. I am still reading up on various pages/questions and trying various things to rule things out, or understand better what is being shown/told to me.
Thank you in advance for the patience to read this question, and sorry for its length.
You have a pretty good understanding of what's happening.
All pages in Next.js depend on _app - it rerenders because of pageProps or more likely Component prop changes - forcing the children to rerender.
The layouts will 'persist' between pages - the children should rerender on a route change but, components that are still on the page should keep their state.
i.e. a search input in the layout should keep its search term on route changes to another page with the same layout.
The only way not to rerender during route change is to use shallow routing . But it doesn't really route - it just allows you to add query params to the current route (can't change pages or it will use standard routing).
As you mentioned, you can use memo on some of your components to prevent rerendering, but only use it when you know you need it and use it wisley.
Lastly, rerendering is also part of React and virtual DOM manipulation, I wouldn't worry about it too much until it becomes a problem.

When a React context state updates does it force a rerender of the child components if its context is not being used?

Just asking before I actually dive into this as this will rewrite a bunch of navigation logic.
Can I have the following structure where I have a list screen and an edit screen as follows
<DataProvider>
<Navigator>
<Screen name="list" component={ComponentThatUseData} />
<Screen name="list different layout" component={ComponentThatUseData} />
<Screen name="list another different layout" component={ComponentThatUseData} />
<Screen name="edit" component={ComponentThatDoesNotUseData}>
</Navigator>
</DataProvider>
If DataProvider has a useState and I update that will it cause a re-rendeer of the edit screen even though the useContext is not invoked? Since a re-render will cause my edit form to lose focus.
Yes, based on what I understand on the React Documentation, one of the caveats of React Context is that when the state in the Context is updated, the children will be affected, I think it's because the Context Provider is still a React Component.
React Context Caveat - Section

React component seems to rerender because of child components (but shouldn't)

I have a page with a tabbed view. If tab 1 is active it should show component A, otherwise component B.
Based on which page/route I come from before, it should default to component B. Both the components don't need props (as they handle data/state internally).
Problem: The parent component renders three times. Because of this, I loose the state value from useLocation and can't display the second tab. Simplified parent component code:
function ContractOverview() {
const location = useLocation();
console.log(location);
const showBillingCycleTab = location.state?.selectedTab === 'billing-cycles';
return (
<Container>
<h1>
<Trans i18nKey="navigation.billing" />
</h1>
{showBillingCycleTab ? <BillingCycleTable /> : <ContractTable />} // if I do it like this, ContractOverview renders three times (and I loose location state)
{showBillingCycleTab ? <p>component A</p> : <p>component B</p>} // if I do it like this, ContractOverview renders only once and the location state is correct.
</Container>
);
}
The route is set up like this:
<Route path="/contracts" component={ContractOverview} exact />
Screenshot of the location logs:
Usually I'd expect the parent component to only render once as there are no props that could change nor component state that could do something. What am I doing wrong?

Link changing URL but not the page

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
}
}

How to get react grand-child node to render when child is out of my control

I have a react component which uses a 3rd party library Component as a Child node. The Grand children (or the children of the 3rd party libary) are under my control. When my component receives new props it re-renders, however the 3rd party component seems to stop my components grand-children from re-rendering also, even though the props my component received, are passed to the non-re-rendering components directly
If I remove the 3rd party component then my component re-renders as do the grand-children.
render() {
<div>
<ThirdPartyComponent props={blah}>
{this.props.products.map(prod => <MyGrandChildrenComponents product={prod} />
</ThirdPartyComponent>
</div>
}
A concrete example can be found on this code sandbox: codesandbox.io/s/silly-grass-7frlx
I'd expect my MyGrandChildrenComponents component to get updated when this.props.products changes... Any hints?
This can happen if ThirdPartyComponent is a stateful component and is not handling its prop updates correctly. One way to force a re-render is to add a key prop to your ThirdPartyComponent and update its value when a re-render is needed.
render() {
<div>
<ThirdPartyComponent key={something-that-changes-when-rerender-needed} props={blah}>
{this.props.products.map(prod => <MyGrandChildrenComponents product={prod} />
</ThirdPartyComponent>
</div>
}
If ThirdPartyComponent is a PureComponent it should re render (and so re render its children) when one of its props changes so you can try:
render() {
<div>
<ThirdPartyComponent props={blah} products={this.props.products}>
{this.props.products.map(prod => <MyGrandChildrenComponents product={prod} />
</ThirdPartyComponent>
</div>
}
To trigger re renders when this.props.products changes.
But any prop should do.
If ThirdPartyComponent has a custom implementation of shouldComponentUpdate, then you will have to find the specific prop which triggers update if it exists.

Resources