Use Component State with React

InstructorKent C. Dodds

Share this video with your friends

Send Tweet

In this lesson we'll build a stopwatch component that maintains its own state. We'll start by creating the static UI, then take the dynamic parts and accept them as props. After that we'll refactor that to state and add event handlers to update the state.

Adam
~ 7 years ago

Hi Kent, awesome course. I'm new to both JS and React. Just wanting to check with you that in the "Use Component State with React" lecture, the "startTime" variable is just a placeholder variable changes in value all the time? Ie, it does not record the actual start time of when I click the start button and later when I click the stop button, the start time has actually "moved". Thanks, Adam

Kent C. Doddsinstructor
~ 7 years ago

Hi! So if you look closely at the logic, we set the start time once you click the start button and then reference that in the setInterval call. So it's set once each time you click start and never changes.

QuarkStudios
~ 7 years ago

Hi! So this the code that i have written for the above practical

class StopWatch extends React.Component{ state = {lapse: 0, isRunning: false}

handleStartClick(){ this.setState({lapse: 10, isRunning: true})

} handleClearClick(){

}

render(){ const {lapse, isRunning} = this.state; return ( <div> <label>{lapse}ms</label> <button onClick={this.handleStartClick}>{isRunning ? 'Stop' : 'Start'}</button> <button onClick={this.handleClearClick}>Clear</button> </div> ) } }

ReactDOM.render(<StopWatch />,document.getElementById('root'))

getting this error on clicking 'start' button

Uncaught TypeError: Cannot read property 'setState' of undefined

and the error is completeley expected because wrong referencing of 'this'

but hows your prac working?

Kent C. Doddsinstructor
~ 7 years ago

Change your implementation to this:

class StopWatch extends React.Component{
  state = {lapse: 0, isRunning: false}
  
  handleStartClick = () => {
    this.setState({lapse: 10, isRunning: true})

  }
  handleClearClick = () => {
    
  }
  
  render(){
        const {lapse, isRunning} = this.state;
    return (
      <div>
        <label>{lapse}ms</label>
        <button onClick={this.handleStartClick}>{isRunning ? 'Stop' : 'Start'}</button>
        <button onClick={this.handleClearClick}>Clear</button>
      </div>
    )
  }
}

ReactDOM.render(<StopWatch />,document.getElementById('root'))

See this video for an explanation about why.

Good luck!

Cornelius
~ 7 years ago

This example code behaves weirdly when run in Firefox on my box. To fix it, I had to pass in a delay parameter to the call to setInterval like so:

this.timer = setInterval(() => {
    this.setState({
	lapse: Date.now() - startTime,})
			}, 100)

see setInterval documentation

Scott Martin
~ 7 years ago

I ran into the same problem as Cornelius on Firefox. It looks like Firefox doesn't work correctly if you don't provide a delay to setInterval. I just explicitly set it to 0 and it fixed the problem.

Mattia Assogna
~ 7 years ago

Hi Kent, thank you for this series of videos. I am trying to implement it in a React project, but it doesn't work. It says syntaxError: Unexpected token =

I am compiling with webpack and babel-loader Thank you

Kent C. Doddsinstructor
~ 7 years ago

Hi mattia, The public class fields syntax (state = {}) is currently a stage-3 proposal in the EcmaScript standardization process of the TC39. This means that it wouldn't be included if you're using babel-preset-env and you'll need to include the babel-plugin-transform-class-properties transform for it in your babel configuration. If you're using create-react-app, it's included by default.

Learn more about the feature from this lesson.

Christiaan Westerbeek
~ 7 years ago

Thanks for the course. Another question about the public class fields. Instead of

handleClearClick = () => {

You could have done this:

handleRunClick() {...}...

The public class field will create a new instance of the methods with each class instantiation, whereas the regular class method is the same thing for each class instance.

The regular class methods would require you to bind the handleRunClick and handleClearClick to this.

Why did you use the public class fields and what do you think are the benefits over the regular class methods?

Christiaan Westerbeek
~ 7 years ago

Wow! You totally explained it in a way that couldn't have been more helpful in lesson 12.

https://egghead.io/lessons/egghead-use-class-components-with-react

PS: Looking back at this discussion, I now see you already mentioned that.

Kent C. Doddsinstructor
~ 7 years ago

Yeah, the order of these particular lessons was a little tricky 😅

Mel
~ 7 years ago

What IDE are you using? I noticed yours has intellisense.

Kent C. Doddsinstructor
~ 7 years ago

I'm using atom

Melissa Clausse
~ 6 years ago

Hi Kent,

I know this is a bit off-topic but can you explain how this.timer in handleClearClick is able to reference the timer from handleRunClick?

Thanks! Melissa.

Kent C. Doddsinstructor
~ 6 years ago

this represents the object which is our instance of the stopwatch component. All the methods there have access to that object and the properties on it. So when handleRunClick sets this.timer, because handleClearClick has access to the same this object it can access this.timer :)

Mahesh K Bepet
~ 5 years ago

Hello Kent, What are you using to make the browser dynamically reflect changes as you type - considering we're updating a plain '.html' file, and don't have a build system like webpack running. Thanks.