首页 文章

在卸载组件后调用Redux setState

提问于
浏览
1

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

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

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

我可以't figure out how to prevent this. Here'下面的代码为 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 回答

  • 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

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

相关问题