Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using useState hooks to update based on the previous state successively

I'm trying to enable button if both the checkboxes are checked, I have nonworking stackblitz link

I have added the only crux of functionality. Please look into the link for the nonworking demo

    import React, { useState } from 'react';
    import { render } from 'react-dom';

    function App (){
      const [checked, toggleCheckbox] = useState({ checkbox1: false, checkbox2: false, disabled: true });
      const getDisabled = (state) => {
         if (state.checkbox1 || state.checkbox2) {
           return false;
         } else if (!state.checkbox1 && !state.checkbox2) {
           return true;
         } else {
           return true;
         }
       };
       const handleCheckbox = (checkbox) => {
        toggleCheckbox({
            ...checked,
            [checkbox]: !checked[checkbox],
            disabled: getDisabled(checked)
        });
        console.log(checked);
    };
    const checkDisable = checked.disabled ? 'disabled' : ''
    return (
      <div>
        <div>
           <label>
               <input
                    type="checkbox"
                    className="filled-in"
                    onChange={() => handleCheckbox('checkbox1')}
                    checked={checked.checkbox1}
                />
                <span className="black-text">Checkbox1</span>
            </label>
        </div>
        <div>
            <label>
                <input
                    type="checkbox"
                    className="filled-in"
                    onChange={() => handleCheckbox('checkbox2')}
                    checked={checked.checkbox2}
                />
                <span className="black-text">checkbox2</span>
            </label>
        </div>
        <div>
            <a className={checkDisable} href="#!">
                Next Step
            </a>
        </div>
   </div>
  );
}
render(<App />, document.getElementById('root'));

The functionality should be as follows:

  1. The button should be enabled only if both the checkboxes are checked
  2. On unchecking anyone checkboxes it should disable the button
like image 401
lost_in_magento Avatar asked Jan 27 '26 01:01

lost_in_magento


1 Answers

You can simply check the state of both checkbox values.

  const isDisabled = !(checked.checkbox1 && checked.checkbox2)
  const checkDisable = isDisabled ? 'disabled' : ''

No need to change elsewhere.

Forked stackblitz link. https://stackblitz.com/edit/react-jscqwr?file=index.js

demo


Answer to the comment.

Hey, that worked! I could see in the log that the state one step below the updated state for an instance after clicking in the first checkbox { checkbox1: false, checkbox: false, disabled: false } after clicking the second checkbox the log { checkbox1: true, checkbox: false, disabled: false }

The reason you are seeing outdated state is because the state updator toggleCheckbox batches the update, thus you'd need to check for the updated status in an effect, which monitors the updated status.

how to console


Dynamic number of checkboxes.

I've updated the stack to track dynamic number of checkboxes.

New fork~ https://stackblitz.com/edit/react-pl1e2n

Looks like this. enter image description here

function App() {
  const length = 6;
  1️⃣ Generate the initial checkbox states - this prevents un/controlled component error.
  const initialCheckboxes = Array
    .from({ length }, (_, i) => i + 1)
    .reduce((acc, id) => (acc[id] = false, acc), {})

  const [checked, toggleCheckbox] = useState(initialCheckboxes);
  const [isDisabled, setIsDisabled] = useState(false)

  const handleCheckbox = id => {
    toggleCheckbox(previous => ({
      ...previous,
      [id]: !previous[id]
    }));
  };

  2️⃣ Update the disable state when the checkbox is selected.
  useEffect(() => {
     👇 Enable when all checkboxes are not checked - 😅
    setIsDisabled(!Object.values(checked).every(_ => !!_))
  }, [checked])

  3️⃣ Dynamically generate checkboxes
  const checkboxElements = Array.from({ length }, (_, i) => i + 1)
    .map(id => (
      <div key={id}>
        <label>
          <input
            type="checkbox"
            className="filled-in"
            onChange={() => handleCheckbox(id)}
            checked={checked[id]}
          />
          <span className="black-text">Checkbox{id}</span>
        </label>
      </div>
    ))


  return (
    <div>
      {checkboxElements}
      <div>
        <a className={isDisabled ? 'disabled' : ''} href="#!">
          Next Step
                            </a>
      </div>
    </div>
  );
}
like image 200
dance2die Avatar answered Jan 29 '26 14:01

dance2die