Creating a mini app to demonstrate the problem I’m having with React & Typescript
Here is a simple toggle component
import { MouseEvent, useState } from "react";
interface ToggleParams {
label?: string;
value?: boolean;
disabled?: boolean;
onToggleClick?: (
event: MouseEvent<HTMLButtonElement>,
value: boolean
) => void;
}
const Toggle = ({
label = "",
value = false,
disabled = false,
onToggleClick = () => {},
}: ToggleParams) => {
const [enabled, setEnabled] = useState(value);
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
if (disabled) return;
console.log("handleClick > enabled", enabled);
const newValue = !enabled;
console.log("handleClick > newValue", newValue);
setEnabled(value);
onToggleClick(event, newValue);
};
return (
<button
onClick={handleClick}
disabled={disabled}
className="focus:outline-none"
>
{`${enabled ? "true" : "false"} ${label}`}
</button>
);
};
export default Toggle;
here is the code that tests this component
import { useState } from "react";
import Toggle from "./Toggle";
export default function App() {
const [toggleAll, setToggleAll] = useState(false);
const [toggleItem, setToggleItem] = useState(false);
const [toggleDisabled, setToggleDisabled] = useState(false);
console.log("Toggle state", toggleAll, toggleItem, toggleDisabled);
const onToggleAllClick = (event: any, value: boolean) => {
setToggleAll(value);
setToggleItem(value);
setToggleDisabled(value);
};
const onToggleItemClick = (event: any, value: boolean) => {
setToggleItem(value);
if (!value) {
setToggleAll(value);
setToggleDisabled(value);
}
};
return (
<div className="App">
<div>
<Toggle
value={toggleAll}
label={"Toggle All"}
onToggleClick={onToggleAllClick}
/>
</div>
<div>
<Toggle
value={toggleItem}
label={"Toggle Item"}
onToggleClick={onToggleItemClick}
/>
</div>
<div>
<Toggle
value={toggleDisabled}
label={"Toggle Disabled"}
disabled={true}
/>
</div>
</div>
);
}
The toggle should change state when I click them, however they don’t on the 1st click
When I click the Item toggle, the console correctly shows
handleClick > enabled false
handleClick > newValue true
Toggle state false true false
indicating that the code works, however the display shows
false Toggle All
false Toggle Item
false Toggle Disabled
which means the toggle component itself didn’t change
clicking it again, then changes the display correctly to this
false Toggle All
true Toggle Item
false Toggle Disabled
the console output doesn’t change
I refresh the page to start again
When I click the All toggle, all the items should be true, and the console correctly shows
handleClick > enabled false
handleClick > newValue true
Toggle state true true true
however the display incorrectly shows
false Toggle All
false Toggle Item
false Toggle Disabled
all these should have changed from false to true
when I click All toggle again, the console is the same, but the display changes to
true Toggle All
false Toggle Item
false Toggle Disabled
toggle All display changed correctly this time, but the others should have changed as well
Bug: toggles need to be clicked twice before they change their own value on the display
now click item toggle (once), the item toggle now displays true and only needed 1 click
now click item toggle again (twice) so that it shows false
the display changes to
handleClick > enabled true
handleClick > newValue false
Toggle state false false false
the code correctly changed all the values to false here in the console according to onToggleItemClick, however the display still incorrectly shows
true Toggle All
false Toggle Item
false Toggle Disabled
Bug: toggles need to be change their value when the underlying value from the code changes
Bug: the disabled toggle should also change its value when the underlying value from the code changes
what do I need to do to correctly show get the toggle to display the correct value?
Here is a sandbox https://codesandbox.io/p/sandbox/vibrant-jackson-44g6xt