<-- /notes<-- /notes/react-101

Component States

Initial States

Components in React also have a special object known as the state. The state object represents the current state of any component instance. It requires a constructor method.

class Example extends React.Component {
  constructor(props) {
    super(props)
    this.state = { title: "An example" }
  }
  render() {
    return <h1>{this.state.title}</h1>
  }
}

Since our component Example is a subclass of React.Component, we call the constructor and the super() function to inherit properties and call the constructor of the parents. Inheritance and class based programming information can be found here: http://exploringjs.com/es6/ch_classes.html.

Changing States

A component doesn't only read it's own state, it can change it's state, using the function this.setState(). React changes states by merging with the old state, preserving what it can. Take a look at this:

// Let's say this was the initial state
{
  mood: 'great',
  hungry: false
}
// We can change the initial states by the following
this.setState({
  hungry: true,
  status: "just ate"
});
// Now if we were to call the 'state' object...
{
  mood: 'great',
  hungry: true,
  status: "just ate"
}

this.setState() can only accept objects, but does using ES6 arrow notation, we can also slip in some easy functions which would return objects. For example:

// initial state
{
amHungry: true,
burgersEaten: 0
}

this.setState({
  amHungry: false,
  burgersEaten: 2
}); // this is hard-coded

this.setState( (currentState) => (
  currentState.burgersEaten ++;
  return {
    amHungry: Boolean(burgersEaten > 1),
    burgersEaten: currentState.burgersEaten
  };
) ); // this is functional

Changing States from Another Function

In order to allow a function to change the state of a component instance, we first need to bind it. That means that we insert a line in the constructor which links the function's operation to that specific instance, rather than every rendered instance of that component. Here's an example:

  constructor(props) {
    super(props);
    this.state = {state: stateValue};
    this.function = this.function.bind(this); // Now the function will only operate on this instance
  }

If we invoke a state change, it needs to be done in a separate function for clarity. Take a look:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {color: '#FDFDFD'};
    this.changeColour = this.changeColor.bind(this);
  }
  changeColor() {
    this.setState(color: this.state.color === '#FDFDFD' ? '#4DCCB0' : '#FDFDFD');
  }
  render() {
    return (
      <button
        style={{background: this.state.color}}
        onClick={this.changeColor}>
        Change Color
      </button>
    );
  }
}

If we were to render this Toggle component, every time the button element is clicked, it's background would change color, even though we aren't re-rendering it, we are just changing the state value. This is because this.setState() automatically invokes the render() function after completing the change.