3

http://jsfiddle.net/NV/f54Xr/

/**
 * @jsx React.DOM
 */

var Dummy = React.createClass({
    mixins: [React.addons.LinkedStateMixin],
    getInitialState: function() {
        return [42, 54];
    },
    render: function() {
        return <div>
            {this.state.map(this.renderItem)}
            <pre>{JSON.stringify(this.state, null, 2)}</pre>
        </div>
    },
    renderItem: function(item, i) {
        return <div>
            <input type="number" valueLink={this.linkState(i)}/>
        </div>
    }
});


React.renderComponent(
    <Dummy/>,
    document.body
);

When I’m changing numbers in the input fields React throws:

Uncaught Error: Invariant Violation: Critical assumptions about the merge functions have been violated. This is the fault of the merge functions themselves, not necessarily the callers.

Is it a bug in React? Is merging arrays not working?

NVI
  • 14,907
  • 16
  • 65
  • 104

1 Answers1

3

Your state is an array.

I didn't see anything in the React doc mentioning the LinkedStateMixin mixin could link an input to an array index.

What happens is probably:

  • Your initial state is [42, 54]
  • If you modify item at index 0, the LinkedStateMixin creates a new state { 0: 43 }

As setState() doesn't override an existing state but merges the new state into the existing state (because you only update one input at a time), then React is trying to merge a JSON object into a JS array. Which is weird :)

Actually your initial values are displayed correctly because both array[index] and object[key] works the same.

I don't think React support arrays well for now but it's worth opening a pull request maybe.

For now you can try to use objects like this:

http://jsfiddle.net/f54Xr/3/

var Dummy = React.createClass({
    mixins: [React.addons.LinkedStateMixin],
    getInitialState: function() {
        return {0: 42, 1: 54};
    },
    render: function() {
        return <div>
            {Object.keys(this.state).map(this.renderItem)}
            <pre>{JSON.stringify(this.state, null, 2)}</pre>
        </div>
    },
    renderItem: function(key) {
        return <div>
            <input type="number" valueLink={this.linkState(key)}/>
        </div>
    }
}); 

By the way you may try to create your own LinkedStateMixin to link to an array index, has you have done there:

React.js 2-way bindings: two-levels deep path in valueLink

I just wonder if it is possible in React to have state = [42, 54] and then setState([undefined, 55]) to finally have state = [42, 55], please tell us :)

Community
  • 1
  • 1
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
  • 4
    "I don't think React support arrays well for now but it's worth opening a pull request maybe." This is right, you can't use an array as the state for a React component. In React v0.9 you'll get a better error message for this. (You can of course have state look like `{items: [42, 54]}` but that won't work with linkState.) – Sophie Alpert Feb 20 '14 at 17:45