Martyn Chamberlin Martyn Chamberlin - 6 months ago 7
Javascript Question

ReactJS component doesn't seem to have isolated scope

I'm new to ReactJS, coming from AngularJS. I want to have a component that has a button and when you click that button it shows a textarea. Given this custom component in React:

Toggle = React.createClass({
UI: {
showNotes: false
},
toggleShowNotes: function () {
this.UI.showNotes = !this.UI.showNotes;
console.log(this.UI.showNotes);
this.setState({UI: this.UI});
},
render: function () {
return (
<div className="well">
<div className="form-group">
<button className="btn btn-default" onClick={this.toggleShowNotes}>+ Add Notes</button>
</div>
{this.UI.showNotes ? <textarea className="form-control" placeholder="Notes"></textarea> : null }
</div>
)
}
});


Notice I'm logging the state of the component's
UI.showNotes
to the console whenever the button is clicked. If I put several of these components inside my main app, like this:

var App = React.createClass({
render: function () {
return (
<div>
<Toggle></Toggle>
<Toggle></Toggle>
<Toggle></Toggle>
<Toggle></Toggle>
<Toggle></Toggle>
</div>
);
}
});

ReactDOM.render(
<App/>,
document.getElementById('container')
);


When I click the
button
, what's logged to the console is always the opposite value of what was previously logged to the console. The problem is that this is true no matter which
<Toggle>
button I click.
In other words, it seems as though there is only ONE instance of
this.UI
instead of one instance per component. That really confuses me, given ReactJS' documentation on the matter:


React takes care of creating an instance for every class component, so you can write components in an object-oriented way with methods and local state, but other than that, instances are not very important in the React’s programming model and are managed by React itself.


I would expect
this.UI
to be unique to each component, not be a "global" object that's shared between all instances of the component.


  1. Why is this not the case?

  2. Since it's not the case, what is the best way for me to restructure my component in order to achieve the desired effect?


Answer

By using

UI: {
    showNotes: false
},

you're essentially creating an object that is shared across all instances because it's defined on the prototype, therefore if you change showNotes, all instances see the change It has nothing to do with React, but with JavaScript.

Instead use something like this:

Toggle = React.createClass({
    getInitialState: function() {
        return {showNotes: true};
    },
    toggleShowNotes: function () {
        this.setState({showNotes: !this.state.showNotes});
    },
    render: function () {
        return (
            <div className="well">
                <div className="form-group">
                    <button className="btn btn-default" onClick={this.toggleShowNotes}>+ Add Notes</button>
                </div>
                {this.state.showNotes ? <textarea className="form-control" placeholder="Notes"></textarea> : null }
            </div>
        )
    }
});
Comments