Why I cannot use method setState() to array elements

Viewed 86

How to change expanded state of every object in array list. I want to change states inside eachClose() function. Every time when I trying change state of objects in array list i got that error from React compiler:

TypeError: item.setState is not a function

class Item extends React.Component{
        constructor(props){
            super(props);

            this.state = {
                expanded: false,
            };
}

class ItemList extends React.Component{
    constructor(props){
        super(props);

        this.state = { 
            list: [ 
                <Item />,
                <Item />,
                <Item />,
                <Item />,
                <Item />,
            ]
        };
    }
    

    eachClose = () => {
        this.state.list.map ((item, i) => item.setState({expanded: false}))
    }

    render(){
        return(
            <div className="users">
                {this.state.list.map ((item, i) => <Item id={i} key={i} />)}
                <button onClick={this.eachClose}>Click</button>
            </div>
        );
    }
}
1 Answers

As already said above, in your case item is not an instance of actual element. Moreover, keeping elements in state is an antipattern.

What you need to to instead - is to keep information about each element in the list state and render items with the information from the list. Like this:

class Item extends React.Component{
        constructor(props){
            super(props);

            this.state = {
                expanded: props.expanded, // idea is to get expanded state from props
            };
     //.... rest of component. btw, probably you do not need state here at all
}    

class ItemList extends React.Component{
        constructor(props){
            super(props);
    
            this.state = { // keep data for items, not items themself
                list: [ 
                    { expanded: true },
                    { expanded: true },
                    { expanded: true },
                    { expanded: true },
                    { expanded: true }
                ]
            };
        }
        
    
        eachClose = () => {
            const newList = this.state.list.map((item) => {
              return { ...item, expanded: false };
            });
            this.setState({ list: newList });
        }
    
        render(){
            // now render list according to info in state
            return(
                <div className="users">
                    {this.state.list.map((item, i) => <Item id={i} key={i} expanded={item.expanded} />)}
                    <button onClick={() => this.eachClose()}>Click</button>
                </div>
            );
        }
    }

Here is a codepen for you: https://codepen.io/tamango/pen/LYbbqZa

Related