在卸载组件后调用Redux setState

问题描述 投票:1回答:2

我正在构建一个具有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

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

reactjs redux
2个回答
2
投票

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

componentWillUnmount() {
  this.unmounted = true;
}

...

someMethod() {
  if (!this.unmounted) this.setState{...}
}

0
投票

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

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或者你可以在设置状态之前检查this.mounted

我不确定这是最好的解决方案,但它确实解决了这个问题

© www.soinside.com 2019 - 2024. All rights reserved.