Rezpo
Rezpo

Reputation: 119

Update each item in state onClick event

I'm trying to update each item in the state by clicking a button. The initial state is FALSE (isSelected) for each item, if users do a onClick event on the button class div it should update the state (isSelected) of the current item to TRUE, but I'm not figuring out how to accomplish this.

EDITED: It should update only one item per click for example if I hit the button for ID: 1 of firsItem it should change isSelected state to true only for ID: 1

This is an example of my code (how a I think it should be)

import React, { Component } from 'react'

export default class List extends Component {
  constructor(props) {
    super(props);
    this.state = {
      listItems: [{
        name: 'firstItem',
        itemOptionSelector: [{
          id: 1,
          isSelected: false
        },
        {
          id: 2,
          isSelected: false
        },
        {
          id: 3,
          isSelected: false
        },
        ]
      },
      {
        name: 'secondItem',
        itemOptionSelector: [{
          id: 1,
          isSelected: false
        },
        {
          id: 2,
          isSelected: false
        },
        {
          id: 3,
          isSelected: false
        },
        ]
      }
      ]
    }
  }

  selectItemClickHandler = () => {
    this.setState({
      listItems: [{itemOptionSelector: [{isSelected: true}]}]
    })
  }

  render() {
    const {listItems} = this.state

    return (
      <div>
        {listItems.map(item => {
          <div className="button" onClick={this.selectItemClickHandler}>{item.name}</div>
        })}
      </div>
    )
  }

}

Upvotes: 0

Views: 919

Answers (3)

Khabir
Khabir

Reputation: 5854

Please check this complete example. Basically you had issue in setting state on click handler.

selectItemClickHandler = () => {
    this.setState({
      listItems: [{itemOptionSelector: [{isSelected: true}]}]
    })
  }

Updated code of selectItemClickHandler should be:

selectItemClickHandler = (event, index) => {
        this.setState(prevState => {
            const list = [];
            prevState.listItems.map((item, i) => {
                if (i === index) {
                    item.itemOptionSelector.map(selector => {
                        selector.isSelected = true
                    })
                }
                list.push(item);
            });
            return {
                listItems: list
            };
        });
    };

Here is the complete example where I have changed the above code

import React, {Component} from 'react'

export default class ListExample extends Component {
    constructor(props) {
        super(props);
        this.state = {
            listItems: [
                {
                    name: 'firstItem',
                    itemOptionSelector: [
                        {id: 1,isSelected: false},
                        {id: 2,isSelected: false},
                        {id: 3,isSelected: false},
                    ]
                },
                {
                    name: 'secondItem',
                    itemOptionSelector: [
                        {id: 1,isSelected: false},
                        {id: 2,isSelected: false},
                        {id: 3,isSelected: false},
                    ]
                }
            ]
        }
    }

    selectItemClickHandler = (event, index) => {
        this.setState(prevState => {
            const list = [];
            prevState.listItems.map((item, i) => {
                if (i === index) {
                    item.itemOptionSelector.map(selector => {
                        selector.isSelected = true
                    })
                }
                list.push(item);
            });
            return {
                listItems: list
            };
        });
    };

    render() {
        const {listItems} = this.state;

        return (
            <div>
                {listItems.map((item, index) => {
                    return <div key={index} className="button" onClick={(event) => {
                        this.selectItemClickHandler(event, index)
                    }}>{item.name}</div>
                })}
                <button onClick={()=>{ console.log(this.state, 'current state') }}>Show State in Console</button>
            </div>
        )
    }
}

Upvotes: 1

Ioannis Potouridis
Ioannis Potouridis

Reputation: 1316

I'm going to post an example because it's not clear what you want to update.

Let's say this is your state.

state = {
  items: [
    {
      id: 1,
      isSelected: false,
    },
    {
      id: 2,
      isSelected: false,
    },
    {
      id: 3,
      isSelected: false,
    }
  ]
};

And this is how you render your items.

<ul>
  {this.state.items.map((item, index) => (
    <li key={item.id} onClick={this.handleToggle(index)}>
      {item.id} {item.isSelected + ""}
    </li>
   ))}
</ul>

Then, your handler needs to look like this.

// pay attention to the handler which creates a closure
handleToggle = index => () => {
  const items = [...this.state.items];

  items[index].isSelected = !items[index].isSelected;

  this.setState({ items });
};

Upvotes: 1

technophyle
technophyle

Reputation: 9128

First of all, it's not clear what you are trying to do. You're not rendering your "sub-items" (or options), so there's no way currently to know which option should be changed to the selected state.

Generally, you update an array state like this:

state = {
  items: [
    { isSelected: false, name: 'first' },
    { isSelected: false, name: 'second' },
    { isSelected: false, name: 'third' },
  ]
};

// ...

handleItemClick = (item, index) => {
  const items = this.state.items.slice();
  items[index] = { ...item, isSelected: !item.isSelected };
  this.setState({ items });
};

render() {
  return this.state.items.map((item, index) =>
    <div onClick={() => this.handleItemClick(item, index)}>{item.name}</div>);
}

Upvotes: 1

Related Questions