Search code examples
javascriptarraysreactjsobject-literal

Can't use array functions like .includes in Object literals


I'm trying to organise my react state in object literals consisting of arrays.

const [state, setState] = React.useState({ filter: [], other: [] });

I want to update my filter array, whenever a click on a list item occurs.

    const handleListItemClick = (event, index) => {
    if (state['filter'].includes(index)) {
        setState(state['filter'].filter(function (element) {
            return element != index;
        }))
    } else {
        setState(state['filter'].concat([index]));
    }
};

But whenever I try to access the filter array, java script can't resolve array functions like includes or indexOf, for instance:

<ListItem
          button
          selected={state['filter'].includes(0)}
          onClick={(event) => handleListItemClick(event, 0)}>
                <ListItemText primary="Kundensegmente" />
</ListItem

I get this error:

Uncaught TypeError: state.filter.includes is not a function

Using functions like includes seems to work in one-dimensional arrays.


Solution

  • The original shape of the state was this:

    { filter: [], other: [] }
    

    But then you changed it:

    setState(state['filter'].concat([index]));
    

    You replaced the whole state with the value of fiter (an empty array) concatinated with a new array [index].

    That new array doesn't have a filter property.


    Use separate states for filter and other.

    const [filter, setFilter] = React.useState([]);
    const [other, setOther] = React.useState([]);
    

    Alternatively, if you really want to keep them merged into a single object, then you need to maintain the shape of that object in the state.

    Create a new object which is the same as the old object except for just the bits you want to change.

    setState({
        ...state,
        filter: state.filter.concat([index]);
    });