0

I have 2 buttons that can be toggled by that simple hook:

  const [extendDetails, setExtendDetails] = useState(false);
  const handleExtendDetails = () => setExtendDetails(!extendDetails);

  const [extendPictures, setExtendPictures] = useState(false);
  const handleExtendPictures = () => setExtendPictures(!extendPictures);

And these are the buttons:

<button onClick={handleExtendDetails}>Extend Details</button>
<button onClick={handleExtendPictures}>Extend Pictures</button>

Is there some sort of way to name the buttons and use e or some kind of a variable so I won't need to declare a hook for each button in case I've got 20 buttons and not just 2?

1
  • Could you put the button in a component? Then you can re-use it over and over again. Commented Jan 17, 2021 at 16:44

2 Answers 2

1

You can try using defining simple Object and target name combination.

const initialState = () => ({
  extendDetails: false,
  extendPictures: false
})

export default function App() {
  const [toggle, setToggle] = useState(initialState())

  const handleToggle = (e) => {
    const { name } = e.target

    setToggle({ ...toggle, [name]: !toggle[name] })
  }
  return (
    <div>
      <button name="extendDetails" onClick={handleToggle}>{toggle.extendDetails ? 'Open' : 'Close' } Extend Details</button>
      <button name="extendPictures" onClick={handleToggle}>{toggle.extendPictures ? 'Open' : 'Close' } Extend Pictures</button>
    </div>
  );
}

Demo link is here

Sign up to request clarification or add additional context in comments.

Comments

1

One option is to use an array instead:

const [toggledButtons, setToggledButtons] = useState(() => Array.from(
  { length: 20 },
  () => false
));

Then you could do something like

const toggle = (i: number) => () => setToggledButtons(
    toggledButtons.map((current, j) => i === j ? !current : current)
);
<button onClick={toggle(0)}>Extend Details</button>
<button onClick={toggle(1)}>Extend Pictures</button>

4 Comments

Seems like toggledButtons is declared but not used. Got this error: Type '() => [boolean[], Dispatch<SetStateAction<boolean[]>>]' is not an array type.
It's not shown in your original code where extendDetails and extendPictures are being used. Replace uses of those variables with toggledButtons[0], toggledButtons[1], etc. You could even use an object instead of an array if you think it'd make things clearer.
I understand, it looks like a good solution. The only issue now is that I use React with TypeScript (tsx file) and I get the only error message: Argument of type '(current: any, j: any) => any' is not assignable to parameter of type 'SetStateAction<boolean[]>'. Type '(current: any, j: any) => any' is not assignable to type '(prevState: boolean[]) => boolean[]'.
If you're using TS, you need to indicate the type of the argument. Since toggle takes a number argument, type the argument as that, a number: i: number

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.