在卸载组件后调用的Redux setState

时间:2018-01-02 01:11:59

标签: reactjs redux

我正在构建一个包含3个主要组件的React / Redux应用程序 - 说明,StoryFeed和测验,我试图循环 4轮(3 + 1练习)。

我有一个时钟组件(它嵌套在StoryFeed中 组件)并且它设置为在计时器时移动到测验组件 命中零。但是,它似乎在调用了setState之后 卸载并给出无限错误

  

警告:setState(...):只能更新已安装或已安装   零件。这通常意味着您在已卸载时调用了setState()   零件。这是一个无操作。

我无法弄清楚如何防止这种情况发生。以下是Clock组件的代码:

import React from 'react'
import PropTypes from 'prop-types'

import ReactInterval from 'react-interval'

class Clock extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0,
      timed: props.timed,
      counting: true
    }

    this.tick = this.tick.bind(this)
  }

  reset() {
    this.setState({
      counting: true,
      count: this.state.count + 1
    })

  }
  componentWillUnmount() {
    this.setState({ counting: false }, () => this.props.complete())
  }
  tick() {
    const { count, timed, counting } = this.state
    if (count + 1 > timed && counting) {
      this.componentWillUnmount()
    } else {
      this.reset();
    }
  }

  render() {
    return (
      <div className="clock alert alert-warning">
        <ReactInterval
          timeout={1000}
          enabled={this.props.timed > 1 && this.state.count < this.props.timed}
          callback={() => this.tick()}
        />
        <span>{this.state.timed - this.state.count}</span>
      </div>
    )
  }
}

Clock.propTypes = {
  timed: PropTypes.number,
  complete: PropTypes.func
}

export default Clock

这里是父组件StoryFeed代码:

import React from 'react'
import Marquee from './Marquee'
import * as stories from '../stories'
import Clock from './Clock'
import { chunk, now } from '../utils'
import PropTypes from 'prop-types'

class StoryFeed extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      text: stories.example,
      currentTest: 1,
      count: 0,
      timed: props.timed,
      selected: []
    }
    this.storyLoad.bind(this)
    this.select = this.select.bind(this)
    this.isSelected = this.isSelected.bind(this)
  }

  componentDidMount() {
    document.body.classList.add('mosaic-full-screen')
    this.storyLoad();
  }

  componentWillUnmount() {
    document.body.classList.remove('mosaic-full-screen')


  }

  select(id) {
    if (this.state.selected.find(s => s.id == id)) return

    this.setState({
      selected: [...this.state.selected, { id, time: now() }]
    })
  }

  isSelected(id) {
    return this.state.selected.find(j => j.id === id)
  }

  storyLoad(state) {
    switch (this.state.currentTest){
      case 1:
      this.setState({text: stories.example});
        console.log(this.state.currentTest)
      break;
      case 2:
      this.setState({text: stories.colleagues});
      break;
      case 3:
      this.setState({text: stories.aroomforthenight});
      break;
      case 4:
      this.setState({text: stories.thepromotion});
      break;
    }
  };



  reset() {
    this.clock &&
      this.clock.reset(4, () => {
        this.setState({
          counting: true
        })
      })
  }


  render() {
    const { enterAnswers, id, show, timed } = this.props
    return (
      <div className="story">
        <div className='container'>
          <Marquee text={this.state.text.join(' - ')} loop={false} hoverToStop={true} />
        </div>
        <div className="controls">
          {timed && (
            <Clock
              timed={timed}
              complete={() => enterAnswers(id, this.state.selected, now())}

            />
          )}
        </div>
      </div>

      )
    }

}
StoryFeed.propTypes = {
  timed: PropTypes.number,

  enterAnswers: PropTypes.func,
  id: PropTypes.number,
  show: PropTypes.oneOf(['window', 'jigsaw'])
}
export default StoryFeed

这个问题的其他答案似乎是个案特定的

2 个答案:

答案 0 :(得分:2)

您可以在卸载时设置方法属性,然后仅在未设置此属性时更新状态。例如:

this.mounted

答案 1 :(得分:0)

解决此问题的一种方法如下

Pattern.quote

现在您可以使用class X extends Component { mounted = false ss = (...args) => { this.mounted && this.setState(...args) } componentDidMount(){ this.mounted = true } componentWillUnMount(){ // or componentDidUnmount this.mounted = false } } 代替this.ss,或者您可以在设置状态之前检查this.setState

我不确定这是最好的解决方案,但确实可以解决问题