2

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 2

2

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.

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

Comments

0

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.

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.