Easy Tutorial
❮ React Ref Componentdidupdate React Jsx ❯

React State

React views components as state machines. By interacting with the user, different states are achieved, and then the UI is rendered to keep the user interface and data consistent.

In React, you only need to update the component's state, then re-render the user interface based on the new state (without manipulating the DOM).

The following example creates an ES6 class that extends React.Component, using this.state in the render() method to modify the current time.

A class constructor is added to initialize this.state, and class components should always call the base constructor with props.

React Example

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

Next, we will make the Clock set its own timer and update every second.

Adding Lifecycle Methods to the Class

In applications with many components, it's important to free up resources taken by the components when they are destroyed.

Whenever the Clock component is first loaded into the DOM, we want to generate a timer, which in React is called mounting.

Similarly, whenever the DOM produced by the Clock is removed, we also want to clear the timer, which in React is called unmounting.

We can declare special methods on the component class to run some code when the component mounts or unmounts:

React Example

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

Example Analysis:

The componentDidMount() and componentWillUnmount() methods are called lifecycle hooks.

The componentDidMount() hook is executed after the component output is inserted into the DOM, allowing us to set a timer on this hook.

this.timerID is the timer's ID, which we can unmount in the componentWillUnmount() hook.

Code Execution Order:

Once the Clock component is removed from the DOM, React will call the componentWillUnmount() lifecycle hook, and the timer will be cleared.

Data Flows Down

Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn't care whether it is defined as a function or a class.

This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.

In the following example, the FormattedDate component will receive the date value in its props and won't know whether it came from the Clock's state, from the Clock's props, or was typed manually:

React Example

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        &lt;FormattedDate date={this.state.date} />
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

This is commonly called top-down or unidirectional data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components below them in the tree.

If you imagine a component tree as a waterfall of props, each component's state is like an additional water source that joins it at an arbitrary point but also flows down.

To show that all components are truly isolated, we can create an App component that renders three Clocks:

React Example

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        &lt;FormattedDate date={this.state.date} />
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Clock />
      <Clock />
      <Clock />
    </div>
  );
}

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

In the example above, each Clock component sets up its own timer and updates independently.

In a React application, whether a component is stateful or stateless is considered an implementation detail of the component that may change over time.

We can use stateless components within stateful components, and vice versa.

❮ React Ref Componentdidupdate React Jsx ❯