What Is The Use Of Functional Syntax Of Setstate In React Functional Components?
Solution 1:
They are not the same, if your update depends on a previous value found in the state, then you should use the functional form. If you don't use the functional form in this case then your code will break sometime.
Why does it break and when
React functional components are just closures, the state value that you have in the closure might be outdated - what does this mean is that the value inside the closure does not match the value that is in React state for that component, this could happen in the following cases:
1- async operations (In this example click slow add, and then click multiple times on the add button, you will later see that the state was reseted to what was inside the closure when the slow add button was clicked)
constApp = () => {
const [counter, setCounter] = useState(0);
return (
<><p>counter {counter} </p><buttononClick={() => {
setCounter(counter + 1);
}}
>
immediately add
</button><buttononClick={() => {
setTimeout(() => setCounter(counter + 1), 1000);
}}
>
Add
</button></>
);
};
2- When you call the update function multiple times in the same closure
constApp = () => {
const [counter, setCounter] = useState(0);
return (
<><p>counter {counter} </p><buttononClick={() => {
setCounter(counter + 1);
setCounter(counter + 1);
}}
>
Add twice
</button></>
);
}
Solution 2:
Problems might occur depending on how fast/often your setter gets called.
If you are using the simple way by getting the value from the closure, subsequent calls between two renders might not have the desired effect.
A simple example:
functionApp() {
const [counter, setCounter] = useState(0);
constincWithClosure = () => {
setCounter(counter + 1);
};
constincWithUpdate = () => {
setCounter(oldCounter => oldCounter + 1);
};
return (<><buttononClick={_ => { incWithClosure(); incWithClosure(); }}>
Increment twice using incWithClosure
</button><buttononClick={_ => { incWithUpdate(); incWithUpdate(); }}>
Increment twice using incWithUpdate
</button><p>{counter}</p></>);
}
Both buttons calls one of the increment methods twice. But we observe:
- The first button will increment the counter only by 1
- The second button will increment the counter by 2, which is probably the desired outcome.
When can this happen?
- Obviously, if
incWithClosure
is called multiple times immediately after each other - If asynchronous tasks are involved, this can easily happen (see below)
- Perhaps, if React has much work to do, its scheduling algorithms may decide to handle multiple very fast clicks using the same event handler
Example with asynchronous work (simulating loading a resource):
functionApp() {
const [counter, setCounter] = useState(0);
constincWithClosureDelayed = () => {
setTimeout(() => {
setCounter(counter + 1);
}, 1000);
};
constincWithUpdateDelayed = () => {
setTimeout(() => {
setCounter((oldCounter) => oldCounter + 1);
}, 1000);
};
return (
<><buttononClick={(_) => incWithClosureDelayed()}>
Increment slowly using incWithClosure
</button><buttononClick={(_) => incWithUpdateDelayed()}>
Increment slowly using incWithUpdate
</button><p>{counter}</p></>
);
}
Click on the first button twice (within one second) and observe that the counter gets incremented only by 1. The second button has the correct behavior.
Solution 3:
Because if you don't you will find at some point that you get an old value for age
. The problem is, sometimes what you suggest will work. But sometimes it will not. It may not break in your current code today but it may break in a different code you wrote a few weeks ago or your current code a few months from now.
The symptom is really, really weird. You can print the value of the variable inside a jsx component using the {x}
syntax and later print the same variable using console.log
after rendering the jsx component (not before) and find that the console.log
value is stale - the console.log
that happens after the render can somehow have older value than the render.
So the actual value of state variables may not always work correctly in regular code - they are only designed to return the latest value in a render. For this reason the callback mechanism in a state setter was implemented to allow you to get the latest value of a state variable in regular code outside of a render.
Post a Comment for "What Is The Use Of Functional Syntax Of Setstate In React Functional Components?"