0

My React state:

//...
this.state = {
    mylist: [
        {
            "id": 0,
            "trueorfalse": false
        },
        {
            "id": 1,
            "trueorfalse": false
        }
    ]
}
//...

I am trying to update the trueorfalse value based on the id

Here is what I did so far but didn't work:

var idnum = e.target.id.toString().split("_")[1] //getting the id via an element id (0 or 1 in this case)
var TorF = true
if (type === 1) {
    this.setState({
        mylist: this.state.mylist.map(el => (el.id === idnum ? Object.assign({}, el, { TorF }) : el))
    })
}

I really want to make it dynamic so the trueorfase will be opposite of what it is now:

var idnum = e.target.id.toString().split("_")[1] //getting the id via an element id (0 or 1 in this case)
if (type === 1) {
    this.setState({
        mylist: this.state.mylist.map(el => (el.id === idnum ? Object.assign({}, el, { /* if already true set to false or vice versa */ }) : el))
    })
}

How can I update my code to have the dynamicity shown in the second example (if possible), otherwise the first example would do just fine

Si8
  • 9,141
  • 22
  • 109
  • 221
  • You could negate the existing property like `!el.trueorfalse` – Michael Aug 19 '19 at 16:35
  • `{ !el.trueorfalse }` didn't work, it instead gave an error – Si8 Aug 19 '19 at 16:37
  • Possible duplicate of [How to update nested state properties in React](https://stackoverflow.com/questions/43040721/how-to-update-nested-state-properties-in-react) – Domino987 Aug 19 '19 at 16:56

2 Answers2

1

Another solution using map:

Edit withered-field-889f8

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      mylist: [
        {
          id: 0,
          trueorfalse: false
        },
        {
          id: 1,
          trueorfalse: true
        }
      ]
    };
  }
  toggleBoolean = () => {
    const ID = Number(this.state.selectedID);
    this.setState(prevState => ({
      mylist: prevState.mylist.map(item => {
        if (item.id === ID) {
          return { ...item, trueorfalse: !item.trueorfalse };
        } else {
          return item;
        }
      })
    }));
  };
  render() {
    return (
      <div className="App">
        <p>{`State values: ${JSON.stringify(this.state.mylist)}`}</p>
        <button onClick={this.toggleBoolean}>Change true/false values</button>
        <label>Insert ID:</label>
        <input
          type="number"
          onChange={event => this.setState({ selectedID: event.target.value })}
        />
      </div>
    );
  }
}
Joss Classey
  • 1,054
  • 1
  • 7
  • 22
  • Oh this also works. Which would be more efficient to use, or it doesn't matter. – Si8 Aug 19 '19 at 18:29
  • 2
    @Si8 I think the performance would be pretty similar because both copy/create a new array and iterate over every element of the existing array. Either way though I think choosing based on efficiency at this point would be micro-optimizing; just pick which way makes more sense in your head. – Michael Aug 19 '19 at 18:49
  • Thanks @Michael for the clarification. – Si8 Aug 20 '19 at 19:42
0

I think the following code would accomplish your second question.

var idnum = e.target.id.toString().split("_")[1]
let newList = Array.from(this.state.mylist) //create new array so we don't modify state directly
if (type === 1) {
    let objToUpdate = newList.find((el) =>  el.id === idnum) // grab first element with matching id
    objToUpdate.trueorfalse = !objToUpdate.trueorfalse
    this.setState( { mylist: newList } )
}
Michael
  • 2,673
  • 1
  • 16
  • 27