Save array of objects in state - ReactJS

22,518

Solution 1

Instrument is an object, and you are trying to render it, use the specific value that you wants to render, Try this:

musicListenChange(val){
    let user = this.state.user;  
    user['music_listen'] = val.value;
    this.setState({user: user);
}

saveInstrument(){
    let user = this.state.user;
    user['instruments'] = user['instruments'] ? user['instruments'] : [];
    user['instruments'].push(this.state.instruments);
    this.setState({user: user});
}

In render function use this:

{this.state.user.instruments ? 
     this.state.user.instruments.map((instrument, index) => {
        return (<button className="btn btn-default">{instrument.name}</button>)
     })
:<div/>
}

Solution 2

The problem is here:

<div className="container-tags">
    {this.state.user.instruments ? this.state.user.instruments.map(function (instrument, index) {
        return <button className="btn btn-default">{instrument}</button>;
    }) : <div></div>}
</div>

When realising that instrument is a JavaScript object (you said that your instruments array contains objects with structure {name: "string", experience:"string"}), the error message becomes clear: you are trying to insert an object as a child of the <button> element, which is not allowed, since React has no idea how to display an object. If you used instrument.name or instrument.experience instead (which are strings), your code will work.

Share:
22,518
The Condor
Author by

The Condor

Updated on March 02, 2020

Comments

  • The Condor
    The Condor about 4 years

    I am building a ReactJS application, and I need to store data in this way:

    this.state = {
        user: {
            name: "",
            surname: "",
            age: "",
            ...
            instruments: [],
        }
    }
    

    The instruments state needs to contain several objects, with properties name and experience. An example:

    instruments: [
        {
            name: 'Bass guitar',
            experience: 7,
        },
        {
            name: 'Drums',
            experience: 1,
        }
        ...
    ]
    

    I'm new to React, so far I have been able to save data in similar arrays by doing this:

    musicListenChange(val){
            let musicListenArray = this.state.user.music_listen ? this.state.user.music_listen : [];
            musicListenArray.push(val.value);
            this.setState({user: {...this.state.user, music_listen: musicListenArray}});
        }
    

    However, when I try to save an object with the following code I receive an error:

    saveInstrument(){
            // save current instruments state in array, or create an empty one 
            let array = this.state.user.instruments ? this.state.user.instruments : [];
    
            // in this.state.instruments I saved a temporary copy of the selected instrument, put it in the array
            array.push(this.state.instruments);
            this.setState({user: {...this.state.user, instruments: array }});
            console.log('instrum. state: ', this.state.user.instruments);
        }
    

    Error code

    Uncaught Error: Objects are not valid as a React child (found: object with keys {name, experience}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `EditProfile`.
    

    My EditProfile render part for the instruments

    <div className="container-tags">
        {this.state.user.instruments ? this.state.user.instruments.map(function (instrument, index) {
            return <button className="btn btn-default">{instrument}</button>;
        }) : <div></div>}
    </div>
    

    Any idea on how to fix this? Thanks

  • The Condor
    The Condor over 7 years
    this.state.instruments is not an array actually, it's an object. So I think the problem is not there.. but thanks for trying
  • Mayank Shukla
    Mayank Shukla over 7 years
    if this.state.instrument is an object then how u r using {instrument} in html, how you are printing an object.
  • Mayank Shukla
    Mayank Shukla over 7 years
    i did some changes, plz check.
  • p4sh4
    p4sh4 over 7 years
    @TheCondor You must be confused, this.state.instruments is definitely an array since you define it like instruments: [] and then do array operations on it, such as push or map. It's an array of objects.
  • The Condor
    The Condor over 7 years
    Perfect, this was the problem! But the other user replied before and suggested the same solution, therefore I gave the right answer to him. Thanks!
  • tonix
    tonix almost 5 years
    I would say that this is considered a bad practice. A new object for user must be recreated each time state changes with setState(), e.g. const user = { ...this.state.user } before changing user, then you can make changes to user and finally call setState({user}). This way you allow your state to work with pure components too, otherwise they won't rerender.