Reputation: 31585
Using hooks, If I call setState
with the same value as the state
, will it rerender the component?
If yes, how can I avoid that?
e.g.
const [state, setState] = useState(foo)
...
// any where in the code
setState(foo)
Considering that foo
can be any thing, such as {}
, true
, props.bar
or a variable from out side of the component (constant).
Upvotes: 35
Views: 21737
Reputation: 1
Looks like react enforce update state twice. So if you set same value and new value, got one more rerender. After, set same value have no effect. Have a look modified stackblitz
import React, { useState, useEffect } from "react";
// const foo = { foo: 'bar' };
let foo = 1
let clicked = 0;
export default ({ name }) => {
const [state, setState] = useState(foo);
console.log("rendered!", foo);
useEffect(() => {
setState(foo);
console.log("state reset!");
});
const handleClick = () => {
console.log("handleClick!");
clicked++;
if(clicked%3 === 0) {
foo++
}
setState(foo);
// setState({ ...foo, bar : 'baz' });
}
return (<div>
<h1>Hello {name}!</h1>
<button onClick={handleClick}>Click Me</button>
</div>);
};
Upvotes: 0
Reputation: 948
If the setState function or even useReducer Hook returns the same value as the current state, React will bail out without rendering the children or firing effects because it uses the Object.is comparison algorithm.
Upvotes: 1
Reputation: 43
may you read this articl , it has good info connect with the subject:
https://stackoverflow.com/a/55374111/17262218
Upvotes: 0
Reputation: 418
A bit late, but I found an odd case in which setting the state with the same value triggers re-render twice and then usually behaves. setting the state to 2 will trigger re-render twice.
any explanation?
export default function App() {
const [state, setState] = React.useState(1);
console.log("App rendered");
console.log({ state });
return (
<div className="App">
<button
onClick={() => {
setState(1);
}}
>
update state with same value
</button>
<button
onClick={() => {
setState(2);
}}
>
update state with different value
</button>
<div>state:{state}</div>
</div>
);
}
Upvotes: 3
Reputation: 2624
just to summarize
if your state is a primitive value(number, string, boolean, ...), then setting the same value using setState hook won't trigger a rerender. If your state is an Object or Array then it will behave differently.
https://overreacted.io/how-are-function-components-different-from-classes/
https://dmitripavlutin.com/value-vs-reference-javascript/
Upvotes: 17
Reputation: 748
It's a js syntax related question, Just like ===
operation.
let times = 0
const init = {name: 'Bob'}
function App() {
const [state, setState] = useState(init)
function modify() {
setState({name: 'Bob'})
}
function modify2() {
setState(init)
}
times ++
return (
<div className="App">
<p>{ times }</p>
<button onClick={modify}>Same Value Will Rerender</button>
<button onClick={modify2}>Same Reference Never Rerender</button>
</div>
);
}
Here's a Code Sandbox
You can rewrite a wrapper method:
let times = 0
const init = {name: 'Bob'}
function App() {
const [state, setState] = useState(init)
function modify3() {
setState2({ name: 'Bob' })
}
function setState2(value) {
if (value.name === state.name) {
return
}
setState(value)
}
times ++
return (
<div className="App">
<p>{ times }</p>
<button onClick={modify3}>Same Value Will Not Rerender Yet</button>
</div>
);
}
Upvotes: 3
Reputation: 39432
It won't re-render the component if you call setState
with the same value.
Try this out:
import React, { useState, useEffect } from "react";
const foo = { foo: 'bar' };
export default ({ name }) => {
const [state, setState] = useState(foo);
console.log("rendered!");
useEffect(() => {
setState(foo);
console.log("state reset!");
});
const handleClick = () => {
console.log("handleClick!");
setState(foo);
// setState({ ...foo, bar : 'baz' });
}
return (<div>
<h1>Hello {name}!</h1>
<button onClick={handleClick}>Click Me</button>
</div>);
};
You'll notice that even when the button is clicked since the value has not changed. it's not re-rendering the Component. If you change the argument that you call setState
with, it will re-render the component.
Here's a Code Sample for your ref.
Try commenting the first setState
and un-commenting the second one inside the handleClick
method to see the difference.
Upvotes: 26