checkbox is not checked reactjs

Viewed 100

I have a checkbox. If the checkbox is checked, the form check should checked. But it doesn't work for me. I have the following code:

import React, { useState } from 'react'
import { Row, Form, Container } from 'react-bootstrap'
import subMenu from '../subMenu.js'

function TestScreen() {
const [test1, setTest1] = useState(subMenu)
const subMenuHandler = (e) => {
    let sMenu = test1
    sMenu.forEach(sm => {
        if (sm._id === Number(e.target.value))
            sm.isChecked = e.target.checked
    })
    setTest1(sMenu)
}

this is my form:

return (
    <Container fluid>
        <Row className="mx-xs-auto">
            <Form>
                <div key='default-checkbox' className="mb-3" >
                    {test1.map(sm => (
                        <Form.Check
                            type="checkbox"
                            id={sm._id}
                            label={sm.nama}
                            key={sm._id}
                            value={sm._id}
                            checked={sm.isChecked}
                            onChange={subMenuHandler}
                        />
                    ))}
                </div>
            </Form>
        </Row>
    </Container >
)

the stat isChecked is successfully change to true, but the formcheck not change to checked,

this is my data:

const subMenu = [
{
    _id: 1,
    nama: 'submenu-1',
    category: 'Electronics',
    harga: 89.99,
    id_menu: 1,
    isChecked: false
},
{
    _id: 2,
    nama: 'submenu-2',
    category: 'Electronics',
    harga: 89.99,
    id_menu: 1,
    isChecked: false
},
{
    _id: 3,
    nama: 'submenu-3',
    harga: 599.99,
    id_menu: 2,
    isChecked: false
},

]

in the state isChecked has change to true, So where i have wrong? I don't undersanding...

2 Answers

Instead of let sMenu = test1, do , let sMenu = [...test1]

Make a copy of your state before updating it so that react can detect that new object reference is available for it to trigger a re-render.

In earlier way you're just pointing to same object (array is also an object) using different variable name.

Also get more understanding of primitives and non-primitives in JS before a deeper dive into any UI framework. Another important concept would be shallow vs deep copying when it comes to object.

To updating state correctly in React you should create a copy of every piece you are modifying, rather than mutating directly. When you do let sMenu = test1, you are passing the same reference not creating a a copy.

You should not only make a copy of your array, but also the objects you desire to change. This could get a little messy for really nested objects, where you would find yourself creating a lot copies.

below an approach that doesn't mutate your state pieces:

const subMenuHandler = (e) => {

    setTest1(sMenu => (
      sMenu.map(sm => {
        if (sm._id === Number(e.target.value)) return sm
        return { ...sm, isChecked: e.target.checked } 
      })
    ))
}

a few things to notice:

  • you create a copy of the object sm that you want to update. you don't mutate it directy like sm.isChecked = e.target.checked;

  • you don't need to use spread operator on your array here if you're using Map since it already returns a new array, and it doesn't mutate anything. if you use the spread operator is ok too, but you would create another interaction that's not necessary in this case. Spread operator is good if your following logic mutates the object itself.

Related