0

I've got a Form that allows multiple check boxes. When a user clicks the checkbox, it is supposed to add the value to an array of objects and when the user unclicks the value is to be removed from the array but this doesn't work unless the value is the last added in the array.

The code:

import React, { useState, useEffect } from 'react';
import { Dialog, DialogTitle, DialogContent, makeStyles, ListItemSecondaryAction } from '@material-ui/core';
import { Button, ButtonToolbar } from 'react-bootstrap';
import Grid from '@material-ui/core/Grid';
import * as FaIcons from 'react-icons/fa';
import './FilterPopup.css'
import { filterData } from './filterData';
import { genresData } from './genresData'

export default function Filter(props) {
    const { title, children, openPopup, setOpenPopup, genres, setGenres } = props;

    const [filtergenres, setFilterGenres] = useState([]);

    var index;

    function verify(elem) {
        for (var i = 0; i < filtergenres.length; i++) {
            var obj = filtergenres[i];
            if (obj.id == elem) {
                console.log(obj);
                index = i;
                console.log(index);
                return true;
            } else {
                return false;
            }
        }
    }

    function changeValue(elem) {

        console.log(elem);

        let newlist = filtergenres;

        if (verify(elem)) {
            console.log(index);
            newlist.splice(index, 1);
            setFilterGenres(newlist);
            console.log(newlist);
            console.log(filtergenres);
        } else {
            newlist.unshift({
                id: elem,
                value: elem
            });
            setFilterGenres(newlist);
            console.log(newlist);
            console.log(filtergenres);
        }
    }

    return (
        <Dialog open={openPopup} className='filterDialog' maxWidth="md">
            <DialogTitle>
                <div className='popupTitle'> Filter </div>
                <Button className='popupCloseBtn' onClick={() => { setOpenPopup(false) }}>
                    <FaIcons.FaTimes />
                </Button>
            </DialogTitle>
            <DialogContent dividers>
                <form className='pop-up-forms'>
                    <label className='popuppart'>
                        Sort By:
                        <select className='filter-sort'>
                            {filterData.map((item, index) => {
                                return (
                                    <option key={index} value={item.value}>{item.title}</option>
                                )
                            })}
                        </select>
                        <Button className='popupSearchSubmitBtn' onClick={() => { }}>
                            submit
                        </Button>
                    </label>
                    <label className='popuppart'>
                        Include Adult:
                        <input
                            className='filterchkbox'
                            name="isAdult"
                            type="checkbox" />
                    </label>
                    <label className='filterGenres'>
                        Genres:

                        <Grid container spacing={1} direction="row" justify="center" alignItems="center">
                            {genresData.map((item, index) => {
                                return (
                                    <Grid item key={index}>
                                        <label className='genresLabel'>
                                            {item.name}
                                            <input
                                                className='filterchkbox'
                                                name="isAdult"
                                                type="checkbox"
                                                value={item.id}
                                                onClick={() => { changeValue(item.id) }} />
                                        </label>
                                    </Grid>
                                )
                            })}

                        </Grid>
                    </label>
                </form>
            </DialogContent>
        </Dialog >
    )
}

The page:

BingeHUB Homepage

In the photo I clicked the options in this order:

Action (value: 28), Adventure (value: 12), Animation (value: 16), Comedy (value: 35) then I unclicked Animation. But the code adds the 16 again. If I click animation again to re-check it then it removes the 16 it just added.

ND-BEAST
  • 67
  • 8
  • Please show all textual information as text, not as a picture of text. People who can't see can't understand the text below the image, whereas if you included the logs as text it would be immediately clear. – Heretic Monkey Aug 06 '21 at 15:22

1 Answers1

0

splice and unshift don't edit array in immutable way (reference stays the same). React's change detection mechanism is triggered by new references only. If you want to still use splice and unshift you can create a copy of your array first (const clone = [...newlist];), call functions on it and then pass it to setFilterGenres. This way reference will change and React will be able to see this change.

Aitwar
  • 839
  • 4
  • 11
  • I already create a copy of the array and I perform the operations on the copies and then replace the array with the edited copy. – ND-BEAST Aug 06 '21 at 16:24
  • Unfortunately, `let newlist = filtergenres;` doesn't create a copy. It simply copies reference to new variable. To properly clone array you should write it like this: `let newlist = [...filtergenres]`. – Aitwar Aug 06 '21 at 16:27