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

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.

Related

Can I preload an image for a component before it gets used in nextjs

I'm close to deploying a project with NextJS, however I noticed that a lot of the images take quite a bit of time to appear on screen.
I've installed sharp and set the priority to true, but even then images appear pretty slowly.
There's one part of the application, where a specific component gets conditionally rendered. That component has a small illustration included (about 30-50kb depending on the type) and it only shows for 2 seconds, since it's a short confirmation for the user.
There's also another page, which has a bigger illustration on it (about 500kb), which I would love to preload, since it takes a good second to load, when the component gets rendered.
Basically what I'd like to do, is fetch the needed images/illustrations ahead of time, before they need to be used, so that they appear instantaneously for the user.
Is there a way to do this in NextJS? Also happy to move away from the Next/Image component and just use img tags to do this.
Not sure whether code helps in this case, but here is how I display the 500kb image:
<div className="result__illustration">
<Image
src={resultIllu}
alt=""
layout="responsive"
objectFit="contain"
priority={true}
/>
</div>
This is possible using new Image() and then adding an src attribute to it. I made a simple example to illustrate a memoized version of this behavior:
codesandbox
const PreloadedImage = preloadImage("https://via.placeholder.com/700x500");
export default function App() {
return (
<div className="App">
<PreloadedImage alt="Placeholder image" />
</div>
);
}
function preloadImage(src) {
const image = new Image();
image.src = src;
return function PreloadedImage(props) {
return <img {...props} src={src} />;
};
}

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

What is this Component and how does it differ from others

I'm self-teaching React and was just wondering if someone could clear something up for me.
I have this component, which seems to be doing everything I need it to:
const Projects = ({ projectData }) => {
const { url } = useRouteMatch();
return (
{projectData.map((project) => (
<div className="project-container" key={project.id}>
<div className="project-image">
</div>
<div>
<h2>{project.name}</h2>
<p>{project.description}</p>
<div>
<Button class="button link_right relative" linkTo={`${url}/${project.id}`} btnText="Explore" />
</div>
</div>
</div>
))}
);
};
export default Projects;
While watching tutorials and reading documentation I'll typically see Function and Class Components but not whatever this is:
const ComponentName = () => {
So, my questions are:
What sort of component is my example known as
What purpose does it
serve when compared to a Function Component or a Class Component,
How would a Function Component or a Class Component need to look in
order to do everything that my example component is currently doing.
Thanks!
Making instance of class is too slow, because of calling constructor and inheritance. Functional components are just functions, there are no such overheads.
In addition, there is how to treat this. In class, entity of this is often unclear and that confused us. Arrow function reduce it, but using class, we must use this. this caused complicated management of state too. And class object has state itself, so it was troublesome.
Function, defined carefully, is easy to keep purity. It has no state itself. It means that state management is not bother us. Data flow is cleared.

ReactDOM.render does not re-render the 2nd element on the list

im having problem with ReactJS, i
on index.js i have:
ReactDOM.render([<App />, <Footer />], document.getElementById('root'));
the problem is that Footer needs to add an 80px padding from the bottom only on certain pages
so on the render method i do
<div>
{isMobile && window.location.pathname.startsWith('/summary') &&
<div style={{height: 80}}></div> }
</div>
but it doesn't re-render when window.location.pathname changes,
i move around the web app and it doesn't change only when i hit F5 it renders correctly on that page.
i tried using events on window but they're aren't invoked as well...
window.addEventListener('locationchange', function(){
console.log('xxxxxxx location changed!');
})
window.addEventListener('hashchange', function(e){console.log('xxxxxx hash changed')});
window.addEventListener('popstate', function(e){console.log('xxxxxxx url changed')});
how i can make it re-render? or make Footer work as React component that can render ?
This is a common problem!
Out of the box, React is configured to operate on a single page (see Single Page Applications), which basically means it deletes what's shown on screen and renders new information when an update is required.
Naturally, simulating the routing behavior that's observable for non Single Page Apps is a little more difficult - check out React Router, which is a library created to tackle this exact issue.

Should i use State or Props in this simple ReactJS page?

i'm rebuilding my portfolio with ReactJS as i'm learning this new language and i have 1 question. Should i use state or props only in a website where no content will need to be updated?
This is my main class:
class App extends Component {
state = {
name: 'My name',
job: 'Desenvolvedor Web'
}
render() {
return (
<div className="App">
<Header name={this.state.name} job={this.state.job}/>
</div>
);
}
}
And this is my Header.js
const Header = (props) => {
return(
<div className="Header">
<div className="conteudo text-center">
<img src="" className="rounded img-circle"/>
<h1>{props.name}</h1>
<h2>{props.job}</h2>
</div>
)
}
I guess my entire one page portfolio will follow this structure path, with not a big use of handles and changes in my DOM.
I'm sorry for this noob question, i'm really trying my best to learn React.
You should use both state and props in conjunction with one another. You're using both in your code perfectly fine. State is something that is managed by a component and can be passed down to a child via the props. A simple way of understanding this is that you can pass down the Parent component's state (App) to the child (Header) in the form of props which is an important concept in React.
State is both readable and writable whereas props are read only. Also, any change in the components state triggers a re-render.
Here, your state acts as the top/root level for the data that can be passed down to other components if it needs to be used again.
See these for more info.
What is the difference between state and props in React?
https://flaviocopes.com/react-state-vs-props/
State is for properties of your component that change and in turn cause your component to re-render. If you are only passing data down to read, props are a more appropriate choice.

Resources