Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with mapping an array of objects in ReactJS

I have an array of objects and I am trying to group the objects by type, like this:

const el = {
    Type1: [
        {
            param1: 1,
            param2: value1,
            position: 1,
            type: 'Type1'
        }, {
            param1: 2,
            param2: value2,
            position: 2,
            type: 'Type1'
        }
    ],
    Type2: [
        {
            param1: 3,
            param2: value3,
            position: 1,
            type: 'Type2'
        }, {
            param1: 4,
            param2: value4,
            position: 2,
            type: 'Type2'
        }, {
            param1: 5,
            param2: value5,
            position: 3,
            type: 'Type2'
        }
    ]
}

The objects in Type property represent choices for radio buttons. This way I set the first choice checked by default:

    const groupBy = (array, key) => {
        return array.filter(o => o.checked != undefined).reduce((result, currentValue) => {
            (result[currentValue[key]] = result[currentValue[key]] || []).push(
                    currentValue);
            return result;
        }, {});
    };

const [state, setState] = useState({
        buttonsTypes: groupBy([...arrayObjects, arrayObjects.map((item, index) => item.position === 1 ? item['checked'] = true : item['checked'] = false)], 'type'),
        selections: arrayObjects.filter(item => item.checked)
    });

My question is how to map this dynamically and change the checked value on click? I tried this so far:

    const selectChoice = (obj) => {
        setState(prevState => {
            return {
                buttonsTypes: ... // Not sure how to update the checked value only for the selection of the specific obj.Type
                selections: ...
            };
        });
    };

{Object.entries(state.buttonsTypes).map((item, index) => {
                                return <React.Fragment>
                                    <div className="some-class"/>
                                    <span id="text">{item[0]}</span>
                                    <div id="radio-button-wrapper">
                                        {item[1].map((choice, index) => {
                                                                        return <label className="label-css">
                                                                            <input type="radio" name={choice.param2} value={choice.param1} checked={choice.checked} onClick={() => selectChoice(choice)}/>
                                                                        </label>
                                                                    })
                                        }
                                    </div>
                                </React.Fragment>
                            })
                        }

Can anyone suggest some examples or another approach on how to solve this?

Update: As suggested in the answer, I solved it this way by keeping only an array of the selected choices for each radio group:

const selectChoice = (obj) => {
        setState(prevState => {
            const sel = prevState.selections;
            const idx = sel.findIndex(item => item.type === obj.type);

            if (idx === -1) {
                sel.push(obj);
            } else {
                sel[idx] = obj;
            }

            return {
                ...prevState,
                selections: sel
            };
        });
    };

Inside the mapping:

{Object.entries(state.groupedArray).map((item, index) => {
                                return <React.Fragment>
                                    <div className="some-class"/>
                                    <span id="text">{item[0]}</span>
                                    <div id="radio-button-wrapper">
                                        {item[1].map((choice, index) => {
                                                                        return <label className="label-css">
                                                                            <input type="radio" name={choice.param2} value={choice.param1} defaultChecked={choice.position === 1} onClick={() => selectChoice(choice)}/>
                                                                        </label>
                                                                    })
                                        }
                                    </div>
                                </React.Fragment>
                            })
                        }

Would appreciate if anyone has any suggestions or comments for improvements.

like image 532
devdev Avatar asked May 01 '26 05:05

devdev


1 Answers

Why not use 'state' to keep track of the index of the checked radio button?

Then inside of {item[1].map((choice, index) => {...}}

you can check whether the currently saved 'state' matches the current index in the input you're trying to return

and update the index of the currently checked radio input by attaching your selectChoice handler

like image 117
Jack Avatar answered May 02 '26 18:05

Jack



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!