0

I mapped over a list of objects to render table rows. Each table row has and input with type checkbox.

const [ isChecked, setIsChecked ] = useState(false);

    const handleChange = (e) => {
        setIsChecked(e.target.checked)
    };

    const tableRow = clonedUsers.map((user, index) => {
        return (
            <tr key={index}>
                <td className='spacer-left' />
                <td className='checkbox'>
                    <div className='pretty p-svg p-curve'>
                        <input type='checkbox' onChange={handleChange} checked={isChecked} />
                        <div className='state p-primary'>
                            <svg className='svg svg-icon' viewBox='0 0 20 20'>
                                <path
                                    d='M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z'
                                    style={{ stroke: 'white', fill: 'white' }}
                                />
                            </svg>
                            <label />
                        </div>
                    </div>
                </td>
                <td className='team-name'>{user.name}</td>
                <td className='team-lead-name d-none d-xl-flex'>{user.position}</td>
                <td className='team-index  d-none d-md-flex'>{user.email}</td>
                <td className='team-lead-rating'>
                    <Link to='/people-settings'>Edit team</Link>
                </td>
                <td className='team-lead-rating'>
                    <Link to='/people-settings'>Deactivate user</Link>
                </td>
            </tr>
        );
    });

When I click on any checkbox, it is marking all of them as checked. What am I doing wrong here? Is there any better way of implementing this?

3 Answers 3

1

You have to extract the checkbox to a separate component or i would say you need to create a separate component to use a local state for it:

export default const Checkbox = props => {

    const [isChecked, setIsChecked] = useState(false);

    const handleChange = e => {
       setIsChecked(!isChecked);
    }

    return (
       <input type='checkbox' onChange={handleChange} checked={isChecked} />
    );
} 

Now you can use this:

<div className='pretty p-svg p-curve'>
    <Checkbox />
Sign up to request clarification or add additional context in comments.

2 Comments

What if it needs to be a controlled component - like parent would need to keep track of the checkbox states? :)
That is where props can be used. :)
1

What am I doing wrong here?

The problem is there's only one state used for all checkboxes.

Is there any better way of implementing this?

You can either use list or object to store the state for each checkbox.

But for quick lookup, I will use object with the following structure:

{ [name]: <checkbox value> }
const [checked, setChecked] = useState({});

const handleChange = (e, name) => {
  setChecked({
    ...checked,
    [name]: e.target.checked
  })
};

<input type='checkbox'
  onChange={(e) => handleChange(e, user.name)}
  checked={checked[user.name]}
/>

Comments

1

I'd keep the checked ids in state e.g.:

const [checked, setChecked] = useState([]);

const handleChange = id => () => {
  setChecked(prev => {
    if (prev.includes(id)) {
      return prev.filter(x => x !== id);
    } else {
      return [...prev, id];
    }
  });
};

Then in my input:

<input
  type='checkbox'
  onChange={handleChange(user.id)}
  checked={checked.includes(user.id)}
/>

A cleaner way to write your handler is with lodash using xor.

import xor from 'lodash/xor';

///
const handleChange = id => () => {
  setChecked(prev => xor(prev, [id]));
};

Comments

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.