Yes, if it's a static form, usually you just use several useState. Because you can make sure the variable(state) names are readable, and it's easy to add new fields (or remove unneeded ones). It might look dumb but the maintainability and readability are better than any kind of "clever code".
But sometimes we may have a more dynamic form. For example, all the fields are from some backend APIs, or you have a huge list/table and the toggle fields don't have any semantic meanings, then of course you have to write the code in a more dynamic way.
Here is an example that uses a useReducer:
const initialState = {
1: { checked: false },
2: { checked: false },
3: { checked: false },
4: { checked: false },
}
function reducer(state, action) {
const { type, payload } = action
switch (type) {
case 'toggle':
return {
...state,
[payload.id]: { checked: !state[payload.id].checked },
}
}
}
const YourComponent = () => {
const [toggleState, dispatch] = useReducer(reducer, initialState)
return (
<div>
{Object.keys(toggleState).map((id) => (
<ToggleSwitch
key={id}
checked={toggleState[id].checked}
onChange={() => dispatch({ type: 'toggle', payload: { id } })}
/>
))}
</div>
)
}
I'm using objects here. An array of objects is also fine, or even a simple array: [false, false, false, false]. I think it depends on your use case.
It's also possible to use just one setState, but useReducer in this case is flexible. You can easily add new actions like checkAll or uncheckAll, and put your logics in the reducer.
And then, you can even extract this to a custom hook. Please check this CodeSandbox https://codesandbox.io/s/stackoverflow-toggles-l9b2do?file=/src/App.js for a full working example.
And just for your reference, I also tried to modify your code and used just useState and an array:
const YourComponent = () => {
const [toggles, setToggles] = useState([
['text 1', true],
['text 2', false],
['text 3', false],
['text 4', false],
])
const handleChange = (index) => {
const newState = [...toggles]
newState[index] = [newState[index][0], !newState[index][1]]
setToggles(newState)
}
return (
<div>
{toggles.map(([text, checked], index) => (
<ToggleSwitch
key={index}
checked={checked}
onChange={() => handleChange(index)}
/>
))}
</div>
)
}