so far I saw two ways to handle toggle
first, set state based on previous state
export default function App() {
const [show, setShow] = useState(false);
const handleClick = () => {
setShow(s => !s);
};
return (
<div>
<div>show: {String(show)}</div>
<button onClick={handleClick}>BTN</button>
</div>
);
}
second, pass the state directly as the argument
export default function App() {
const [show, setShow] = useState(false);
const handleClick = () => {
setShow(!show);
};
return (
<div>
<div>show: {String(show)}</div>
<button onClick={handleClick}>BTN</button>
</div>
);
}
which one is correct? In my understanding the second may not work as set state is async, it may not be able to get the correct state if I click the button several times
js import React, { useState } from "react"; import styled from "styled-components"; import { menuData } from "./menuData"; import NavigationButton from "./NavigationButton"; const Menu = () => { const [isOpen, setIsOpen] = useState(false); return ( <Wrapper> <NavigationButton onClick={() => setIsOpen(!
The sample React button component that toggles between on and off is provided below. import React, { useState } from 'react'; import ReactDOM from 'react-dom'; const buttonToggle = () => { const [isOff, setIsOff] = useState(true); return ( <button onClick={() => setIsOff(! isOff)}>{ isOff ?
Hooks are a more direct way to use the React features you already know — such as state, lifecycle, context, and refs. They don't fundamentally change how React works, and your knowledge of components, props, and top-down data flow is just as relevant.
The first one is correct:
setShow(s => !s);
Although the second one works in this case it is not correct:
// bad code
setShow(!show);
Why?
Setting state is asynchronous - but what that really means is that setting state is deferred until re-render.
An example:
const [myNum, setMyNum] = useState(0)
const handleUpdate = () => {
setMyNum(myNum + 1)
}
If we call the handleUpdate
function, the new value of myNum
is incremented by 1. That works correctly, but what about this:
const [myNum, setMyNum] = useState(0)
const handleUpdate = () => {
setMyNum(myNum + 1)
setMyNum(myNum + 1)
}
You may think that myNum
is now 2, but it's not, it's still 1.
This happens because the value of myNum
does not change until re-render, so you're essentially writing this:
const handleUpdate = () => {
setMyNum(0 + 1)
setMyNum(0 + 1)
}
That is why you should always provide a function to set state if you depend on the previous value.
This works correctly:
const handleUpdate = () => {
setMyNum(p => p + 1)
setMyNum(p => p + 1)
}
myNum
is now 2.
Even if you're only setting the value once, you should maintain good practice. When your app gets complex and several different actions may set the state at any time, you don't want to be caught out by something you wrote months ago that you never thought was going to matter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With