loading...

What is State in React?

kritirai profile image Kriti Rai ・3 min read

In English, state refers to "the particular condition that someone or something is in at a specific time" and that holds true in React as well. State is basically a JavaScript object that stores a component's data that are prone to changes, enabling a component to keep track of the changing information in between renders. That's what makes components reactive in nature.

The Why

If you have a static app, don't use state. However, if you want your app to be interactive, like for example a clock widget that shows and updates time at a set interval or an app where one can log in and out, add, delete and update resources - it will involve state.

But, wait a minute don't we use props to store data in components? Yes, but the crucial difference here is that props are immutable (read-only) in that the components can not change their props as they are passed down from parent components. In contrast, component has a full control over its state and can modify it.

The How

Let's look at an example (inspired by the ticking clock example in React docs) to see how state works.

We will build a simple Countdown component that renders the final countdown to the New Year's day.

countdown_gif

Keep in mind,

state is a feature only available in classes

So, let's start by building an ES6 class for our component and write some pseudo code inside to show what it should do.

import React from 'react'
import ReactDOM from 'react-dom';

export default class Countdown extends React.Component {

 timer () {
 // some function that updates the  countdown
 }

 render () {
  return ( 
  // shows the countdown 10 through 1 and renders the message HAPPY NEW YEAR!!
  )
 }
}

const element = <Countdown />

ReactDOM.render(element, document.getElementById('root'));

Now, in order to manipulate the state, you ought to have something to begin with, right? Yup, an initial state. So, let's do that - let's declare the initial state of the component and give it an attribute of secondsLeft. We'll start with 10 secondsLeft and do a countdown until it's 0 secondsLeft. Now, where shall we declare the initial state? Constructor function it is! Because that's what fires before our component is mounted, making it the perfect candidate for setting up defaults including the initial state. Let's add the following block inside our component class.

constructor() {
  super();
  this.state = { secondsLeft: 10}
}

Make sure to pass in props as an argument to constructor() and super() if you wish to use this.props within the class.

Now, let's work on our timer() function that updates our component's state of secondsLeft by subtracting 1 from it.

timer = () => {
 if (this.state.secondsLeft > 0) {
  this.setState({ secondsLeft: this.state.secondsLeft - 1 })
 }
}

We use this.setState() to update a component's state rather than doing something like this.state = someValue

Calling this.setState() tells React that the component's state has updated and that the component needs to be re-rendered.

Also, notice that I used an arrow function to define timer. This is to bind the keyword this to the instance of the component we are working with.

Moving on, let's add a lifecycle method componentDidMount() which will run after the component output has been rendered in the DOM. This is also a good place to call timer(). So, starting with the initial state, with every second the state of the component updates as timer() fires, thus re-rendering the component every second.

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

Here's the final code:

import React from 'react';
import ReactDOM from 'react-dom';

export default class Countdown extends React.Component {
  constructor() {
    super();
    this.state = { secondsLeft: 10 }
  }

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

 timer = () => {
  if (this.state.secondsLeft > 0) {
     this.setState({ secondsLeft: this.state.secondsLeft - 1 })
  }
 }

  render() {
    const message =  (this.state.secondsLeft === 0 )? <font color="red">Happy New Year!!!</font> : this.state.secondsLeft 
    return <h1>{ message }</h1>
  }
}

const el = <Countdown  />

ReactDOM.render(el, document.getElementById('root'));

...aaaaand Action!!

countdown_gif

TL;DR

  • If you want interactive components use state
  • State is a feature only available within class components
  • React maintains state as an object which can be accessed through this.state
  • State is similar to props, but is private and fully controlled by the component and can not be accessed and modified outside the component (think encapsulation)
  • Don't set the state directly like this.state = someValue but use this.setState() instead

Resources:

Discussion

pic
Editor guide
Collapse
karataev profile image
Eugene Karataev

With hooks it's possible to have state in functional components nowdays.

Collapse
kritirai profile image
Kriti Rai Author

Great, i'll have to look into that :)

Collapse
jackharner profile image
Jack Harner 🚀

Thanks for this! Great write-up and it was the first time I've ever been able to say: "Wait, I already know something about React!".

Collapse
kritirai profile image
Kriti Rai Author

Right on! I'm glad you found the post useful :)