【问题标题】:React throws error when using ajax before redirectReact 在重定向之前使用 ajax 时会抛出错误
【发布时间】:2018-12-02 10:23:16
【问题描述】:

我收到以下错误:

警告:无法在未安装的设备上调用 setState(或 forceUpdate) 零件。这是一个无操作,但它表明您的内存泄漏 应用。要修复,取消所有订阅和异步任务 在 componentWillUnmount 方法中。 在 ViewMessage 中(由 Route 创建)

这里是有问题的组件,如您所见,没有componentWillUnmount:

class ViewMessage extends React.Component{
  state={
    message: {},
    messageId: '',
    redirect: false,
    reply: false
  }

  static getDerivedStateFromProps(props, state){
    if(props.location.state){
      return { messageId: props.location.state.id };
    }else{
      return { redirect: true}
    }
  }

  componentDidMount(){
    this.getMessage()
  }

  getMessage = () => {
    this.setState({_loading: true});
    axios({
      method: 'get',
      url: 'http://localhost:8080/getMessage',
      params: {
        id: this.state.messageId
      },
      withCredentials: true
    }).then((result) => {
      this.setState({message: result.data[0], _loading: false});
    })
  }

  handleReply = () => {
    if(this.state.reply){
      this.setState({reply: false});
    }else{
      this.setState({reply: true});
    }
  }


  render(){

    if(this.state.redirect){
      return(
        <Redirect to='/messages' />
      )
    }

    return(
      <Container>
        {this.state.loading ? <Loader active /> : <div></div>}
        <div style={{float: 'right'}}>
          {this.state.message.date}
        </div>
          From: {this.state.message.senderName}
        <Divider />
          Subject: {this.state.message.subject}
        <Divider />
          {this.state.message.text}
        <Divider />
        <Button icon='reply' onClick={this.handleReply}/>
        {this.state.reply ? <Composer recipient={this.state.message.senderName}/> : <div></div>}

      </Container>

    )
  }
}

export default ViewMessage;

添加以下行时出现错误,删除后消失:

    if(this.state.redirect){
      return(
        <Redirect to='/messages' />
      )
    }

我在渲染方法中做错了吗?

【问题讨论】:

  • 您是否在 ajax 调用的响应返回之前重定向?从错误消息中,听起来您在卸载组件后尝试设置状态,而我看到的唯一可能的地方是在您的 ajax 调用之后的.then()

标签: reactjs


【解决方案1】:

Promise 是一个有保证的未来,这意味着一旦调用整个 Promise 链就会触发,您几乎无法阻止它。

在实际层面上,这意味着您需要在尝试访问 setState 之前检查以确保您的 this 上下文仍然存在,因为组件可能在此承诺链完成之前已卸载。

getMessage = () => {
    this.setState({_loading: true});
    axios({
      method: 'get',
      url: 'http://localhost:8080/getMessage',
      params: {
        id: this.state.messageId
      },
      withCredentials: true
    }).then((result) => {
        if (this) { // be sure the instance still exists!
          this.setState({message: result.data[0], _loading: false});
        }
    })
  }

【讨论】:

  • 这似乎是一种非常常见的模式,可以防止用户在返回 ajax 之前卸载组件时出现错误......但我从未见过。此外,它实际上并不能防止错误。
【解决方案2】:

也许试试三元语句?我知道三元语句通常是人们有条件地返回不同组件的方式。

render(){
  return(
    this.state.redirect ?
      <Redirect to='/messages' />
    :
      <Container>
        {this.state.loading ? <Loader active /> : <div></div>}
        <div style={{float: 'right'}}>
          {this.state.message.date}
        </div>
          From: {this.state.message.senderName}
        <Divider />
          Subject: {this.state.message.subject}
        <Divider />
          {this.state.message.text}
        <Divider />
        <Button icon='reply' onClick={this.handleReply}/>
        {this.state.reply ? <Composer recipient={this.state.message.senderName}/> : <div></div>}

      </Container>
  )
}

【讨论】:

  • 我可能知道它为什么这样做。它听起来就像您正在设置this.state.redirect,这会触发组件重新加载。当组件重新加载时,它会重定向到/messages,但是您已经触发了一个在组件已经卸载后尝试 setState 的方法?这听起来像是可能发生的事情吗?
  • 某种,我删除了 componentDidMount() 并且它有效。我需要一种方法来重定向并防止组件调用 componentDidMount() 编辑:它不是在重定向后调用 componentDidMount,而是根据上面的用户,ajax 在卸载后设置状态。有趣....
【解决方案3】:

解决方案有点hacky,是这样的:

  componentDidMount(){
    if(!this.state.redirect){
      this.getMessage()      
    }
  }

这会阻止 getMessage 在安装后发生重定向时被调用。

【讨论】:

    猜你喜欢
    • 2019-11-10
    • 1970-01-01
    • 2014-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-01
    • 2017-05-07
    相关资源
    最近更新 更多