1

I'm struggling with setting the state of one of my objects in React. The code which I have:

export class RRHN_App extends React.Component {
   constructor(props) {
      super(props);
      this.startLoadingItems();
      this.fetchData();
      this.state = {
         items: [],
         itemStatus : [],
         selectedItem: null,
         prefsDialog: false,
         preferences : {
             color : "brown",
             listSize : 800
         }
      }
   }
   toggleItem(item) {
      console.log("Selected item: ", item);
      if( this.state.selectedItem &&
          item.id === this.state.selectedItem.id) {
         this.setState({selectedItem: null});
      } else {
         let ItemID= item.id;
         let newSeen = {ItemID : "seen"};
         this.setState({selectedItem: item});
         this.setState({itemStatus: newSeen});
      }
      console.log(this.state.itemStatus)
   }
   fetchData() {
        request.get("http://localhost:3000/itemStatuses")
            .end( (err,response) => {
                this.setState({itemStatus: response.body})
            })
    }
   startLoadingItems() {
        request.get("http://localhost:3000/hn/topstories")
            .end( (err,response) => {
                this.setState({items : response.body})
            })
    }
}

When printing the itemStatus I get this:

{16490176: "seen", 16497964: "seen", 16514428: "read", 16542395: "read", 16566536: "read"}

When the code is executed the itemStatus looks like this:

{ItemID: "seen"}

How can I add a key-value pair of the item.id and "seen" to the state?

Anna Jeanine
  • 3,975
  • 10
  • 40
  • 74
  • 1
    Try `{ [ItemID] : "seen"}` instead. Key is by default string. When you have a variable as key, you should use destructuring pattern`[]` so that it is parsed first. – Rajesh Mar 12 '18 at 10:07
  • @Rajesh AWESOME! But this still overwrites the old data: {16567009: "seen"}.. – Anna Jeanine Mar 12 '18 at 10:08
  • 1
    @AnnaJeanine can you explain what do you mean by overwrite the old data? – Mayank Shukla Mar 12 '18 at 10:11
  • 1
    @Rajesh `this.setState({itemStatus: Object.assign( {}, this.state.itemStatus, { [ItemID] : "seen" })} )` did the trick thanks to your comment! Could you post this as an answer so I can accept? – Anna Jeanine Mar 12 '18 at 10:12
  • @AnnaJeanine I deleted the comment as it is wrong. Though it is solving your solution, React handles it automatically. If you can explain what you mean about *overwriting old data* and possibly share some more information, it would help – Rajesh Mar 12 '18 at 10:14
  • You define `itemStatus` as an array but set an object `newSeen` to it. Change the line to: `let newSeen = [{ItemID : "seen"}];` – Jun Bach Mar 12 '18 at 10:20

1 Answers1

9

Additionally to the dynamic key Rajesh pointed out, also note the setState will shallow merge existing and new state: Try

this.setState({[ItemId]: 'seen'})
Markus
  • 1,598
  • 2
  • 13
  • 32
  • This gives an error on the spread operator: BabelLoaderError: SyntaxError: Unexpected token (42:24). `this.setState({itemStatus: Object.assign( {}, this.state.itemStatus, { [ItemID] : "seen" })} )` did the trick for me! – Anna Jeanine Mar 12 '18 at 10:14
  • Mh, also I just read up on the docs and it should actually merge... https://reactjs.org/docs/state-and-lifecycle.html#state-updates-are-merged – Markus Mar 12 '18 at 10:15
  • Strange syntax error you have. This is valid ES 6 syntax, maybe there is a problem with your babel setup. But the way you did it is also valid, just oldschool ^^ – Markus Mar 12 '18 at 10:18
  • @Markus its a valid syntax but not a part of es6, array spread has been included not object, check the [mdn doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals) :) – Mayank Shukla Mar 12 '18 at 10:23
  • @MayankShukla Thanks, our babel still supports that though... But I guess it's a bit off topic ^^ – Markus Mar 12 '18 at 10:25