Skip to content

Tried to convert to Es6 with class but keep getting setState() on unmounted component Error #15

@jasan-s

Description

@jasan-s

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.

keeps coming up,
my attempt:

import React, { Component, PropTypes } from 'react'

export default class CountDownTimerContainer extends Component {
  static propTypes = {
    initialTimeRemaining: PropTypes.number.isRequired,
    interval: PropTypes.number,
    formatFunc: PropTypes.func,
    tickCallback: PropTypes.func,
    completeCallback: PropTypes.func
  }

  constructor (props) {
    super(props)
    this.state = {
      timeRemaining: this.props.initialTimeRemaining,
      timeoutId: null,
      prevTime: null,
      isMounted: true
    }
  }

  componentWillMount () {

  }

  componentDidMount () {
    // this.setState({isMounted: true})
    this.tick()
  }

  componentWillReceiveProps (newProps) {
    if (this.state.timeoutId) {
      clearTimeout(this.state.timeoutId)
    }
    if (this.state.isMounted) {
      this.setState({prevTime: null, timeRemaining: newProps.initialTimeRemaining})
    }
  }

  componentDidUpdate () {
    if ((!this.state.prevTime) && this.state.timeRemaining > 0 && this.state.isMounted) {
      this.tick.bind(this)
    }
  }

  componentWillUnmount () {
    clearTimeout(this.state.timeoutId)
    this.setState({isMounted: false})
  }

  tick () {
    const currentTime = Date.now()
    const dt = this.state.prevTime ? (currentTime - this.state.prevTime) : 0
    const interval = this.props.interval

    // correct for small variations in actual timeout time
    const timeRemainingInInterval = (interval - (dt % interval))
    let timeout = timeRemainingInInterval

    if (timeRemainingInInterval < (interval / 2.0)) {
      timeout += interval
    }

    const timeRemaining = Math.max(this.state.timeRemaining - dt, 0)
    const countdownComplete = (this.state.prevTime && timeRemaining <= 0)
    console.log('countdownComplete: ', countdownComplete)

    if ((this.state.isMounted)) {
      if (this.state.timeoutId !== null) {
        console.log('this.state.timeoutId: ', this.state.timeoutId)
        clearTimeout(this.state.timeoutId)
      }
      this.setState({
        timeoutId: countdownComplete ? null : setTimeout(this.tick.bind(this), timeout),
        prevTime: currentTime,
        timeRemaining: timeRemaining
      })
    }

    if ((countdownComplete)) {
      if (this.props.completeCallback) {
        this.props.completeCallback()
      }
      return
    }

    if (this.props.tickCallback) {
      this.props.tickCallback(timeRemaining)
    }
  }

  getFormattedTime (milliseconds) {
    if (this.props.formatFunc) {
      return this.props.formatFunc(milliseconds)
    }

    var totalSeconds = Math.round(milliseconds / 1000)

    var seconds = parseInt(totalSeconds % 60, 10)
    var minutes = parseInt(totalSeconds / 60, 10) % 60
    var hours = parseInt(totalSeconds / 3600, 10)

    seconds = seconds < 10 ? '0' + seconds : seconds
    minutes = minutes < 10 ? '0' + minutes : minutes
    hours = hours < 10 ? '0' + hours : hours

    return hours + ':' + minutes + ':' + seconds
  }

  render () {
    var timeRemaining = this.state.timeRemaining
    return (
      <div className='timer'>
        {this.getFormattedTime(timeRemaining)}
      </div>
    )
  }
}

CountDownTimerContainer.defaultProps = {
  interval: 1000,
  formatFunc: null,
  tickCallback: null,
  completeCallback: null
}

// Generic Countdown Timer UI component
//
// https://github.com/uken/react-countdown-timer
//
// props:
//   - initialTimeRemaining: Number
//       The time remaining for the countdown (in ms).
//
//   - interval: Number (optional -- default: 1000ms)
//       The time between timer ticks (in ms).
//
//   - formatFunc(timeRemaining): Function (optional)
//       A function that formats the timeRemaining.
//
//   - tickCallback(timeRemaining): Function (optional)
//       A function to call each tick.
//
//   - completeCallback(): Function (optional)
//       A function to call when the countdown completes.
//

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions