When i create several instances of a react class (by using React.createElement on the same class), some member variables are shared between the instances (arrays and objects are shared, strings and booleans etc. not).
For me this feels horrible and scary and wrong. Is this a bug or is there another way to do what i want to do?
Please have a look: ,js,console,output
When i create several instances of a react class (by using React.createElement on the same class), some member variables are shared between the instances (arrays and objects are shared, strings and booleans etc. not).
For me this feels horrible and scary and wrong. Is this a bug or is there another way to do what i want to do?
Please have a look: http://jsbin./kanayiguxu/1/edit?html,js,console,output
Share Improve this question edited Apr 21, 2015 at 22:20 tbodt 17k7 gold badges61 silver badges86 bronze badges asked Apr 17, 2015 at 10:55 delijahdelijah 832 gold badges3 silver badges7 bronze badges 4- 2 "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Complete, and Verifiable example." – T.J. Crowder Commented Apr 17, 2015 at 10:57
- I suggest you post the (relevant) parts of the code on SO, and you might also want to check out JavaScript docs on scope in JavaScript: smashingmagazine./2009/08/01/… – Ted Nyberg Commented Apr 17, 2015 at 10:58
- 1 @TedNyberg: From the description, this has nothing to do with scope. It has to do with the difference between primitives and object references on prototypes, most likely. – T.J. Crowder Commented Apr 17, 2015 at 10:59
- @T.J.Crowder That sounds about right. Could remend the following link to the OP: stackoverflow./questions/518000/… – Ted Nyberg Commented Apr 17, 2015 at 11:05
1 Answer
Reset to default 12What you should be doing is setting state on your ponent, instead of having state as arbitrary properties on your React ponent.
So instead of doing this:
var MyComponent = React.createClass({
myArray: [1, 2, 3],
ponentWillMount() {
this.myArray.push(this.myArray.length + 1);
},
render() {
return (
<span>{this.myArray.length}</span>
);
}
});
You should be doing this:
var MyComponent = React.createClass({
getInitialState() {
return {
myArray: [1, 2, 3]
};
},
ponentWillMount() {
this.setState(state => {
state.myArray.push(state.myArray.length + 1);
return state;
});
},
render() {
return (
<span>{this.myArray.length}</span>
);
}
});
The reason being that all of a ponents state and data should reside in this.state
and this.props
which is controlled and handled by React.
The benefit you get from using props and state for this, is that React will know when those change, and from that it can tell when it's time to re-render your ponent. If you store state as arbitrary properties or globals, React won't know when those change, and cannot re-render for you.
The reason for the behaviour you're seeing is that every instance of the ponent uses the object you give to React.createClass()
as its prototype. So all instances of the ponent has a myArray
property, but that is on the prototype chain, and thus shared by all instances.
If you truly want something like this and you want to avoid this.state
, you should use something like ponentWillMount
and inside that method, assign properties to this
. This will make sure that such data is only on that particular instance, and not on the prototype chain.
EDIT
To even further clearify, it can be good to know that the object passed to React.createClass()
isn't the actual object on the prototype. What React does is that it iterates over all properties on that object, and copies them onto the prototype of the React element object. This can be illustrated by this example:
var obj = {
myArray: [1, 2, 3],
title: 'My title',
ponentWillMount() {
this.myArray.push(this.myArray.length + 1);
},
render() {
return (
<span>{this.myArray.length}</span>
);
}
}
var MyComponent = React.createClass(obj);
// This doesn't change the ponent, since 'obj' isn't used anymore
// by React, it has already copied all properties.
obj.title = 'New title';
// This however affects the ponent, because the reference to the array
// was copied to the ponent prototype, and any changes to what the
// reference points to will affect everyone who has access to it.
obj.myArray.push(666);