[React] Stop Memory Leaks with componentWillUnmount Lifecycle Method in React

In this lesson we'll take a stopwatch component we built in another lesson and identify and fix a memory leak.

<body>
<script src="https://unpkg.com/react@16.0.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
<div ></div>

<script type="text/babel">
class StopWatch extends React.Component {
  state = {lapse: 0, running: false}
  handleRunClick = () => {
    this.setState(state => {
      if (state.running) {
        clearInterval(this.timer)
      } else {
        const startTime =
          Date.now() - this.state.lapse
        this.timer = setInterval(() => {
          this.setState(
            {
              lapse: Date.now() - startTime,
            },
            () => {
              console.log(this.state.lapse)
            },
          )
        })
      }
      return {running: !state.running}
    })
  }
  handleClearClick = () => {
    clearInterval(this.timer)
    this.setState({lapse: 0, running: false})
  }
  componentWillUnmount() {
    clearInterval(this.timer)
  }
  render() {
    const {lapse, running} = this.state
    const buttonStyles = {
      border: '1px solid #ccc',
      background: '#fff',
      fontSize: '2em',
      padding: 15,
      margin: 5,
      width: 200,
    }
    return (
      <div center'}}>
        <label
          style={{
            fontSize: '5em',
            display: 'block',
          }}
        >
          {lapse}ms
        </label>
        <button
          onClick={this.handleRunClick}
          style={buttonStyles}
        >
          {running ? 'Stop' : 'Start'}
        </button>
        <button
          onClick={this.handleClearClick}
          style={buttonStyles}
        >
          Clear
        </button>
      </div>
    )
  }
}

class App extends React.Component {
  state = {showStopWatch: true}
  render() {
    const {showStopWatch} = this.state
    return (
      <div>
        <label>
          Show Stop Watch{' '}
          <input
            type="checkbox"
            checked={showStopWatch}
            onChange={() =>
              this.setState(s => ({
                showStopWatch: !s.showStopWatch,
              }))}
          />
        </label>
        <hr />
        {showStopWatch ? <StopWatch /> : null}
      </div>
    )
  }
}

const element = <App />
ReactDOM.render(
  element,
  document.getElementById('root'),
)
</script>
</body>

Tow things to notice here is that:

1. this.setState(), we can pass an update function, which take param 'state' and return a new state

this.setState((state) => ({newState}))

2. Pass a second param to setState() as a callback:

this.setState(newState, callback)