1

I am using the react-addons-update npm package with my React application and specifically want to use the update() method for inserting an new object deep within an array of objects. I have this structure as part of my component state:

...
constructor(props) {
    super(props);
    this.state = {
        blocks: [
            {
                block_title: "some title",
                items: [
                    {
                        item_title: "foo"
                    },
                    {
                        item_title: "bar"
                    }
                ]
            },
            {
                ...
            }
        ]
    };
}
...

and I want to insert a new item into the items array, between the first and second item.

I have tried this:

...
insertItem(){
    let obj = {
        item_title: "in between foo and bar"
    };
    this.setState({
        blocks: update(this.state.blocks, {
            [0]: {
                items: {$splice: [[1, 0, obj]]}
            }
        })
    });
}
...

but this does not seem to be working (no errors are being thrown either). Any ideas?

p.s. I am using React within a Meteor application - just in case there is some quirk that prevents this helper function from working .

JoeTidee
  • 24,754
  • 25
  • 104
  • 149
  • What is the update method? Is blocks an `Immutable.List`? If so, I think you need to use `updateIn`, and you would need to reconstruct the array separately before passing it into the `updateIn` method. – RocketGuy3 Aug 24 '16 at 23:04
  • The update() method is a helper function from the react-addons-update npm package. – JoeTidee Aug 24 '16 at 23:06
  • 1
    looks like your code should work. could it be related to something different than update ? if you were to log your update function what is the result ? – pizzarob Aug 25 '16 at 00:59
  • I logged the output after the update statement and the item is not anywhere within the structure of 'blocks'. Not sure what's going on!? – JoeTidee Aug 25 '16 at 08:34
  • 1
    Are you doing things any different? It works for me here: https://jsfiddle.net/j3dv1spu/ – tobiasandersen Aug 25 '16 at 08:47

2 Answers2

0

Can't see your other methods in the component, but try making sure key prop on the element you render for the added items is there and unique.

goldbullet
  • 602
  • 4
  • 10
  • I am using console.log to print out the state of 'blocks' after the update has been made, so having a key isn't relevant in this case.. – JoeTidee Aug 25 '16 at 11:48
  • 1
    Is your console.log in componentDidUpdate or render? setState updates the state asynchronously, so state may not be updated right after your setState just yet. – goldbullet Aug 25 '16 at 11:57
0

As per goldbullet's comment, setState updates the components state asynchronously. I discovered that a process that ran subsequent to setState in the code block was actually getting the components state before it had been updated. Therefore, the above syntax in the original question is correct for inserting an object deep within an array of objects.

As a solution, I used the setState callback option as below:

...
insertItem(){
    let obj = {
        item_title: "in between foo and bar"
    };
    this.setState({
        blocks: update(this.state.blocks, {
            [0]: {
                items: {$splice: [[1, 0, obj]]}
            }
        })
    },function(){
        // DO SOMETHING HERE!!
    });
}
...

This was also mentioned in this post Why calling react setState method doesn't mutate the state immediately?

Community
  • 1
  • 1
JoeTidee
  • 24,754
  • 25
  • 104
  • 149