简体   繁体   English

正确卸载React组件

[英]Properly unmount React component

Question: Why is this warning being thrown after the component is no longer being rendered by its parent? 问题:为什么在组件不再由其父级呈现后引发此警告? Am I missing something that needs to be done for unmounting of this component rather than just filtering the store state being passed down the hierarchy of components as props? 我是否缺少卸载该组件所需要做的事情,而不是仅过滤沿组件层次结构向下传递的存储状态作为道具?

I've seen this scenario thrown around a lot, but the solution is usually something that involves unsubscribing the redux store from the component; 我已经看到了很多情况,但是解决方案通常涉及从组件退订Redux存储。 however, this component is not connected to the store, just top-level container. 但是,此组件未连接到商店,仅连接到顶级容器。

  • The remove action simply filters the store state to remove the array element responsible for the current component. remove操作仅过滤存储状态以删除负责当前组件的数组元素。
  • The refresh action is currently just a simulation for UI animation events in a child component. refresh操作当前仅是子组件中UI动画事件的模拟。
  • Warning is only thrown when I remove a Feed component after calling the refresh action 仅在调用refresh操作后删除Feed组件时才会引发警告

Warning: setState(...): Can only update a mounted or mounting component. 警告:setState(...):只能更新已安装或正在安装的组件。 This usually means you called setState() on an unmounted component. 这通常意味着您在未安装的组件上调用了setState()。 This is a no-op. 这是无人值守。 Please check the code for the Feed component. 请检查Feed组件的代码。

// @flow
// Feed.js

import React, { Component } from 'react'
import type { FeedType, FeedState } from '../../utils/types'
import { remove, refresh } from '../../actions/redux-actions'
import RssEventList from '../containers/RssEventList'

const cardColors: Array<string> = ['red', 'orange', 'olive', 'green', 'blue', 'yellow']

export default class Feed extends Component {
  props: FeedType
  state: FeedState

  constructor(props: *) {
    super(props)

    this.state = {
      reloading: false
    }
  }

  refresh() {
    this.setState({ reloading: true })
    setInterval(() => this.setState({ reloading: false }), 4000)
    this.props.dispatch(refresh(this.props.link))
  }

  remove() {
    this.props.dispatch(remove(this.props.link))
  }

  render() {
    const color: string = cardColors[Math.floor(Math.random() * cardColors.length)]

    return (
      <div className={`ui ${color} card`}>
        <div className="content">
          <div className="ui header">
            {this.props.title}
            <a className="source link" href={this.props.link} target="_blank">
              <i className="linkify right floated icon"></i>
            </a>
          </div>
          <div className="meta">
            {this.props.description}
          </div>
        </div>
        <div className="content">
          <RssEventList reloading={this.state.reloading} events={this.props.feed} />
        </div>
        <div className="extra content">
          <span className="left floated" onClick={() => this.refresh()}>
            <i className="refresh icon"></i>
            Refresh
          </span>
          <span className="right floated" onClick={() => this.remove()}>
            <i className="cancel icon"></i>
            Remove
          </span>
        </div>
      </div>
    )
  }
}

If it helps, here is a diagram of the component hierarchy: 如果有帮助,请参见下面的组件层次结构图:

App (connected to store)
|- Header
|- FilterBar
|- FeedList
   |- Feed
      |- RssEventList
         |- RssEvent
   |- AddCard

The problem is that you are not storing your interval on component to remove it when component unmounts. 问题是您没有将间隔存储在组件上,因此在卸载组件时将其删除。 Therefore, the interval will continue to be called even after the component is unmounted. 因此,即使在卸载组件后,该间隔也将继续被调用。 You need to remove it with clearInterval() : 您需要使用clearInterval()将其删除:

export default class Feed extends Component {
  refresh() {
    this.myInterval = setInterval(() => this.setState({ reloading: false }), 4000)
  }

  componentWillUnmount() {
    clearInterval(this.myInterval);
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM