1

我正在尝试使用以下组件代码显示倒数计时器但我不断收到警告。

“警告 setState(...):只能更新已安装或正在安装的组件”

但是,我假设我只是在检查我的 isMounted 状态变量在整个组件中是否为真之后才设置状态。我的错误在哪里?

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: false
    }
  }

  componentWillMount () {
    this.setState({isMounted: true})
  }

  componentDidMount () {
    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 () {
    this.setState({isMounted: false})
    clearTimeout(this.state.timeoutId)
  }

  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)

    if (this.state.isMounted) {
      if (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
}

更新:即使在删除之后

this.setState({isMounted: true}) 

从 ComponentWIllMount 并将其添加到构造函数,因为this.state({isMounted: true})我仍然得到 setStateError。

4

1 回答 1

1

.setState()在组件安装之前,您确实做了 a ( componentWillMount())。您不能这样做,因为该组件尚不存在。而是将其置于constructor()初始状态。

于 2016-10-20T12:35:55.283 回答