Why does useState cause the component to render twice on each update? - javascript

I have this simple bit of code here
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [number, setNumber] = useState(0);
function chaneNumber() {
setNumber(state => state + 1);
}
console.log("here");
return (
<div className="App">
<button onClick={chaneNumber}>Change number</button>
{number}
</div>
);
}
Every time I click the button, I get 2 logs in my console indicating that the component renders twice. I found one post saying this is about strict mode, but I have not enabled strict mode. Why is this component rendering twice on each state update?
Here is a codesandbox link to try it out.

Your App component is rendered within React.StrictMode which is what causes your code to run in strict mode and in strict mode the consoles are shown twice because each function is made to run twice in development mode
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
According to react docs:
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer

Related

Re-rendering in React functional component - why this behavior?

This question concerns the definition of callback functions inside functional components, with the callback functions being passed down as props to child functional components.
I am aware that when defining functions inside functional components and those functions are being passed on as props to child components we should use useCallback. In this example I am deliberately not using it.
I have a dummy React app as below:
App.jsx
import { useState, useCallback } from 'react';
import './App.css';
import TestComponent from './components/TestComponent';
import TestComponent2 from './components/TestComponent2';
function App() {
const [message, setMessage] = useState("");
console.log('Defining myArrowfunc');
const myArrowFunc = () => console.log('Hello!');
console.log('myArrowfunc defined');
return (
<>
<TestComponent message={message} myArrowFunc={myArrowFunc} />
<TestComponent2 myArrowFunc={myArrowFunc} />
<input
type="text"
value={message}
onChange={e => setMessage(e.target.value)}
/>
<button
type="button"
onClick={() => {
console.log('Setting message');
setMessage("x");
}}>Set to x</button>
</>
);
}
export default App;
TestComponent.jsx
import { useEffect } from 'react';
function TestComponent(props) {
useEffect(() => {
console.log(`TestComponent.useEffect, props.message = ${props.message}`);
}, [props]);
return <h2>TestComponent - {props.message}</h2>;
}
export default TestComponent;
TestComponent2.jsx
import { useEffect } from 'react';
function TestComponent2(props) {
useEffect(() => {
console.log(`TestComponent2.useEffect`);
}, [props.myArrowFunc]);
return <h2>TestComponent2 - Placeholder</h2>;
}
export default TestComponent2;
Starting the app, the page loads and we are here:
In the console window everything looks like expected. The console.log statements Defining myArrowFunc and myArrowFunc defined ran, and we can see the console.log statements from the useEffect hook within TestComponent and TestComponent2 which ran after they were rendered.
Now we click on the button Set to x, which invokes the callback function attached to the onClick event of the button. This callback calls setMessage("x") which updates the state of the App component and consequently triggers a re-render of the component.
In the console window we can see that the App functional component ran (e.g. from the console.log("Defining myArrowFunc)) and one can also see that the useEffect hooks of the child components ran after they were re-rendered.
Now, that TestComponent re-rendered is of course understandable. message state is a prop on TestComponent which would cause a re-render of TestComponent. Also, in the dependency array of TestComponent is specified props (not props.message), but props is a new object on every render (right?) and hence the reference comparison tells us props has changed and so useEffect runs.
That the useEffect hook of TestComponent2 ran can be understood (right?) from the fact that myArrowFunc is re-defined on each render of App, and so the prop passed to TestComponent2 has in fact changed (reference comparison).
Here comes the part where I become confused: the message state in App now holds "x", and so additional clicks to the button will not change the state, and so should not trigger a re-render of App (and any child components dependant). When I click the button the following output happens:
The statements console.log('Defining myArrowfunc'); and console.log('myArrowfunc defined'); ran. What does this mean? Did the component re-render? If the App function ran, then it should have defined a new myArrowFunc (right?), and since TestComponent2 takes that as a prop, it should have re-rendered and run its useEffect hook?
What's interesting as well is that when I again click the button, it does not look like App ran, the output becomes only "Setting message".
Would very much appreciate an outline / explanation of what exactly is going on here.
When you click the button, a console log with setting message will run, and then a setState with will make a re-render.
At the following click, react is clever enough to see that the state you are setting is the same as before so it doesn't re-render
If you change then, the value and click the button, it will re-render, but not for the following cases with the same value.
To sum up, the first's console.log won't run if there's not a re-render, and the procedure of react--if default--memoizing will prevent it

React Hooks: Why I have this output?

I'm studying React hooks but i am not able to understand why I got this output in the console. Someone with great heart could explain in detail the "running execution" oh these hooks?
import { useState, useEffect } from "react";
function Homepage() {
const [state, setState] = useState();
useEffect(() => {
console.log("useEffect");
console.log("useEffect not executed");
setState("hello")
}, []);
if (!state) {
console.log("state not defined");
return <div>State undefined</div>;
}
return <div>ciao</div>;
}
export default Homepage;
console output:
state not defined
state not defined
useEffect
useEffect not executed
useEffect
useEffect not executed
Basically it's a combination of React.StrictMode double invoking the function body twice as a way to help you detect unexpected side-effects
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies <-- this
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
remounting the component to ensure reusable state
To help surface these issues, React 18 introduces a new
development-only check to Strict Mode. This new check will
automatically unmount and remount every component, whenever a
component mounts for the first time, restoring the previous state on
the second mount.
and the useEffect hook being called at the end of the render cycle.
function Homepage() {
const [state, setState] = useState();
useEffect(() => {
console.log("useEffect"); // logs second as expected side-effect
console.log("useEffect not executed");
setState("hello");
}, []);
if (!state) {
console.log("state not defined"); // logs first as unintentional side-effect
return <div>State undefined</div>;
}
return <div>ciao</div>;
}
...
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import Homepage from "./Homepage";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<Homepage />
</StrictMode>
);
Explaining the logs
console output:
state not defined // <-- initial render
state not defined // <-- double invocation of function body
useEffect // <-- effect at end of initial render
useEffect not executed // <-- effect at end of initial render
...unmount/mount
useEffect // <-- effect at end of render
useEffect not executed // <-- effect at end of render
useEffect runs when the page renders and the other functions execute before useEffect so your code runs the if (!state) first then useEffect runs and state sets to "hello"; here is a link to fully understand useEffect hook: useEffect; Good luck;
your if statement is running before the useEffect even tho is after it, you need to put both divs inside the return and remove the if
return (
{!state ? <div>State undefined</div> : <div>ciao</div>}
)
state not defined first render of your component Homepage
state not defined 2nd render
useEffect useEffect not executed your component is mounted, so the useEffect hook is triggered.
useEffect useEffect not executed here your component rerender with the state hello the useEffect hook is triggered again
In practice, useEffect hook runs at minimum following your dependency array. Here your set [] so the useEffect hook runs when the component mounts, but sometimes it can still be triggered.

React component doesn't show correct render count [duplicate]

I am new to react and I am trying to develop a simple web app with it but I get an error.
My Constructor is called twice when I load a class component can you help?
Home.js
import React from 'react'
import Land from "../Land";
function Home() {
return (
<div>
<h1>Home!</h1>
<Land/>
</div>
)
}
export default Home
Partial Land.js
import React, { Component } from 'react'
import Login from "./Login";
class Land extends Component {
constructor(props) {
super(props)
this.state = {
}
console.log("LAND")
}
the log LAND is hit twice.
In some of the components I wish to make an API call that hits a DB but I only want to hit it once.
In many instances using componentDidMount is not convenient because props only appear after componentDidMount therefor id like to do the call in render(I will not be using setState, that would cause a reload of render).
Thanks in advance
You are using <StrictMode/> and it's development mode
While in <StrictMode/>, react will detect unexpected side effects which will call lifecycle functions more than once duration the development mode, will not be trigger twice in production.
From docs:
why is called twice
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
will not call twice
Note:
This only applies to development mode. Lifecycles will not be double-invoked in production mode.
I didn't quite get what are you trying to say in the comment, but you totally can call function that fetches data within componentDidMount hook
Here's an example:
https://codesandbox.io/s/react-calls-constructor-twice-q5gzs

React useState hook - setState causing multiple re-renders [duplicate]

I have this simple bit of code here
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [number, setNumber] = useState(0);
function chaneNumber() {
setNumber(state => state + 1);
}
console.log("here");
return (
<div className="App">
<button onClick={chaneNumber}>Change number</button>
{number}
</div>
);
}
Every time I click the button, I get 2 logs in my console indicating that the component renders twice. I found one post saying this is about strict mode, but I have not enabled strict mode. Why is this component rendering twice on each state update?
Here is a codesandbox link to try it out.
Your App component is rendered within React.StrictMode which is what causes your code to run in strict mode and in strict mode the consoles are shown twice because each function is made to run twice in development mode
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
According to react docs:
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer

Why does react compute render twice before initial load?

I was under the impression that react render computes once and compares it with DOM to make the change?
However, from my simple example: https://codesandbox.io/s/admiring-rain-ej8fu?file=/src/App.js it seems even before the component mounts. The render function is exceuted twice. I've also included a screenshot below to clarify my point. In the console you can see console.log(value) is evaluated twice. I wonder what conceptual mistake I'm making here!
Code:
import React, { useState, useEffect } from "react";
function Load() {
const [value, setValue] = useState("intial Value");
console.log(value);
useEffect(() => {
console.log("mounted");
}, []);
return (
<div>
<h1>{value}</h1>
<button onClick={e => setValue(Math.random())}>Update state</button>
</div>
);
}
export default Load;
Screenshot:
react initial reload error
It is because codesandbox uses React Strict Mode. React Strict Mode is for better debugging, so, after rendering it reruns all the lifecycle methods to make sure they're "safe". You can reead more about it here. So, just remove React.StrictMode tag in index.js file.

Categories

Resources