尝试在超时时重定向时,React / TypeScript`错误:已超过最大更新深度。

时间:2019-12-09 17:27:18

标签: reactjs typescript timeout setstate

我有一个项目,试图将其从第1页动态重定向到第2页。以前这对我有用,但是最近我遇到了这个错误:

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

今天早上看到此消息,并且有多个SO页面说不打setState中的render之后,我将setTimeout的呼叫移到了componentDidMount中。

到目前为止,我已经尝试过  -调用更改this.props.pageWillChange属性的函数,然后在渲染中根据该条件返回一个对象  -返回内联if语句中的对象挂起条件集  -将pageWillChange变成本地道具,而不是由类继承的道具(我非常喜欢此选项,因为此组件的每个新版本的状态都相同)

还有更多的东西,但是这些感觉好像它们会起作用。有人能帮忙吗?

import React, { Component } from "react"
import axios from "axios"
import { GridList, GridListTile } from "@material-ui/core"

import "../assets/scss/tile.scss"
import Request from "../config.json"
import DataTile from "./DiagnosticDataTile"
import { IDiagnosticResultData } from "../interfaces/IDiagnosticResultData"
import { Redirect } from "react-router"

interface IProps {
  category: string
  redirect: string
}

interface IPageState {
  result: IDiagnosticResultData[]
  pageWillChange: boolean
}

class Dashboard extends Component<IProps, IPageState> {
  _isMounted = false
  changeTimeInMinutes = 0.25
  willRedirect: NodeJS.Timeout

  constructor(props: Readonly<IProps>, state: IPageState) {
    super(props)
    this.state = state
    console.log(window.location)
  }

  componentDidMount(): void {
    this._isMounted = true
    this.ChangePageAfter(this.changeTimeInMinutes)

    axios
      .get(Request.url)
      .then(response => {
        if (this._isMounted) {
          this.setState({ result: response.data })
        }
      })
      .catch(error => {
        console.log(error)
      })
  }

  componentWillUnmount(): void {
    this._isMounted = false
    clearTimeout(this.willRedirect)
  }

  ChangePageAfter(minutes: number): void {
    setTimeout(() => {
      this.setState({ pageWillChange: true })
    }, minutes * 60000)
  }

  render() {
    var data = this.state.result
    //this waits for the state to be loaded
    if (!data) {
      return null
    }

    data = data.filter(x => x.categories.includes(this.props.category))

    return (
      <GridList
        cols={this.NoOfColumns(data)}
        cellHeight={this.GetCellHeight(data)}
        className="tileList"
      >
        {this.state.pageWillChange ? <Redirect to={this.props.redirect} /> : null}
        {data.map((tileObj, i) => (
          <GridListTile
            key={i}
            className="tile"
          >
            <DataTile data={tileObj} />
          </GridListTile>
        ))}
      </GridList>
    )
  }
}

export default Dashboard

(React和TypeScript的新功能,我的第一个SO帖子!)

1 个答案:

答案 0 :(得分:0)

尝试以下代码,也要注意几点:

  • 不需要_isMounted字段。 “ componentDidMount”中的代码始终在安装后运行。
  • 无需在构造函数中设置状态。实际上,不再需要构造函数。
  • clearTimeout挂载中,我看不到componentWillUnmount的重点。它从未分配过超时。

关于路由。 U可以使用“ changePageAfter”方法以编程方式更改“ withRouter”高级功能。

希望这会有所帮助!

import axios from "axios"
import { GridList, GridListTile } from "@material-ui/core"

import "../assets/scss/tile.scss"
import Request from "../config.json"
import DataTile from "./DiagnosticDataTile"
import { IDiagnosticResultData } from "../interfaces/IDiagnosticResultData"
import { Redirect, RouteComponentProp } from "react-router"

interface PropsPassed {
  category: string
  redirect: string
}

type Props = PropsPassed & RouteComponentProp

interface IPageState {
  result: IDiagnosticResultData[]
  pageWillChange: boolean
}

class Dashboard extends Component<Props, IPageState> {
  changeTimeInMinutes = 0.25
  willRedirect: NodeJS.Timeout

  componentDidMount(): void {
    this.ChangePageAfter(this.changeTimeInMinutes)

    axios
      .get(Request.url)
      .then(response => {   
          this.setState({ result: response.data })
      })
      .catch(error => {
        console.log(error)
      })
  }

  changePageAfter(minutes: number): void {
    setTimeout(() => {
      this.props.history.push({
        pathname: '/somepage',
  });
    }, minutes * 60000)
  }

  render() {
    var data = this.state.result
    //this waits for the state to be loaded
    if (!data) {
      return null
    }

    data = data.filter(x => x.categories.includes(this.props.category))

    return (
      <GridList
        cols={this.NoOfColumns(data)}
        cellHeight={this.GetCellHeight(data)}
        className="tileList"
      >
        {data.map((tileObj, i) => (
          <GridListTile
            key={i}
            className="tile"
          >
            <DataTile data={tileObj} />
          </GridListTile>
        ))}
      </GridList>
    )
  }
}

export default withRouter(Dashboard)