当前位置: 首页 > 知识库问答 >
问题:

警告:设置状态(…):无法在redux/immutable的现有状态转换期间更新

公羊绪
2023-03-14

我得到了错误

警告:设置状态(…):无法在现有状态转换期间更新(例如在render或其他组件的构造函数中)。渲染方法应该是道具和状态的纯函数;构造函数的副作用是一种反模式,但可以移动到componentWillMount

我发现原因是

const mapStateToProps = (state) => {
  return {
    notifications: state.get("notifications").get("notifications").toJS()
  }
}

如果我不返回通知那里工作。但这是为什么呢?

import {connect} from "react-redux"
import {removeNotification, deactivateNotification} from "./actions"
import Notifications from "./Notifications.jsx"

const mapStateToProps = (state) => {
  return {
    notifications: state.get("notifications").get("notifications").toJS()
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    closeNotification: (notification) => {
      dispatch(deactivateNotification(notification.id))
      setTimeout(() => dispatch(removeNotification(notification.id)), 2000)
    }
  }
}

const NotificationsBotBot = connect(mapStateToProps, mapDispatchToProps)(Notifications)
export default NotificationsBotBot

import React from "react"

class Notifications extends React.Component {
  render() {
    return (
      <div></div>
    )
  }
}

export default Notifications

更新

在进一步调试时,我发现,以上可能不是根本原因,毕竟,我可以保留通知,但我需要删除调度(推送(/域))我的重定向。

我是这样登录的:

export function doLogin (username, password) {
  return function (dispatch) {
    dispatch(loginRequest())
    console.log("Simulated login with", username, password)
    setTimeout(() => {
      dispatch(loginSuccess(`PLACEHOLDER_TOKEN${Date.now()}`))
      dispatch(addNotification({
        children: "Successfully logged in",
        type: "accept",
        timeout: 2000,
        action: "Ok"
      }))
      dispatch(push("/domains"))
    }, 1000)
  }
}

我发现是调度引起了警告,但为什么?“我的域”页面当前没有太多内容:

import {connect} from "react-redux"
import DomainsIndex from "./DomainsIndex.jsx"

export default connect()(DomainsIndex)

域索引

export default class DomainsIndex extends React.Component {
  render() {
    return (
      <div>
        <h1>Domains</h1>
      </div>
    )
  }
}

更新2

我的pp.jsx。

  <Provider store={store}>
    <ConnectedRouter history={history}>
      <Layout>
        <Panel>
          <Switch>
            <Route path="/auth" />
            <Route component={TopBar} />
          </Switch>

          <Switch>
            <Route exact path="/" component={Index} />
            <Route path="/auth/login" component={LoginBotBot} />
            <AuthenticatedRoute exact path="/domains" component={DomainsPage} />
            <AuthenticatedRoute exact path="/domain/:id" component={DomainPage} />
            <Route component={Http404} />
          </Switch>
          <Notifications />
        </Panel>
      </Layout>
    </ConnectedRouter>
  </Provider>

共有3个答案

裴俊迈
2023-03-14

发生这种情况的原因是当您调用doLogin时,如果您从构造函数中调用它。如果是这种情况,请尝试将其移动到组件WillMount,尽管您应该从按钮调用此方法或在登录表单中输入命中。

如果这不是问题的根源,那么构造函数中已经记录了这一点。您可以在doLogin中对每一行进行注释,以准确知道哪一行给出了状态问题,我猜可能是推送或添加通知

傅正阳
2023-03-14

我以前遇到过这个问题,并使用redux批处理操作解决了它。

这对于像你这样的用例非常有用,当你一次分派多个操作,并且你不确定更新何时会被触发,这样,多个操作只有一个分派。在你的例子中,似乎后续的addNotify很好,但是第三个太多了,可能是因为它与历史api交互。

我会尝试做这样的事情(假设你的setTimeout当然会被一个api调用所取代):

import { batchActions } from 'redux-batched-actions'

export function doLogin (username, password) {
  return function (dispatch) {

    dispatch(loginRequest())
    console.log("Simulated login with", username, password)

    setTimeout(() => {

      dispatch(batchActions([
        loginSuccess(`PLACEHOLDER_TOKEN${Date.now()}`),
        addNotification({
          children: "Successfully logged in",
          type: "accept",
          timeout: 2000,
          action: "Ok"
        }),
        push("/domains")
      ]))

    }, 1000)
  }
}

请注意,您必须下载该软件包,并在商店创建过程中启用批处理。

万开畅
2023-03-14

您的分派(推送('/Domain'))还附带了其他分派,这些分派设置了在推送生效后重新加载/卸载的连接组件(大概是关心通知的组件)的状态。

作为一种解决方法和概念证明,请尝试使用嵌套的零秒setTimeout延迟分派(push('/domains'))调用。这应该在任何其他操作完成后执行推送(如渲染):

setTimeout(() => dispatch(push('/domains')), 0)

如果这行得通,那么您可能需要重新考虑您的组件结构。我认为通知是一个组件,您希望挂载一次,并在应用程序的生命周期内保持它。通过将其放在组件树的较高位置,并使其成为PureComponent(这里是文档)来避免重新加载它。此外,如果应用程序的复杂性增加,您应该考虑使用库来处理异步功能,如redux-saga。

即使此警告通常由于错误的操作调用而出现(例如,在呈现时调用操作:onClick={action()}而不是作为lambda传递:onClick={()=

 类似资料:
  • 在进一步的调试中,我发现,以上可能不是根本原因,毕竟,我可以保留通知,但我需要删除我的重定向。

  • 我正在开发一个简单的待办事项列表反应应用程序(新的React.js)。我已经将项目添加到工作列表中,但删除项目会引起一个问题。在我的父反应组件中,我有以下代码: 我的组件: 运行此代码将带来: 警告:setState(...):无法在现有状态转换期间更新 问题: 为什么的渲染在添加项时立即执行回调,即: 但是,添加以删除Callback ie。

  • 问题内容: 我正在尝试从渲染视图重构以下代码: 到绑定位于构造函数内的版本。原因是渲染视图中的绑定会给我带来性能问题,尤其是在低端手机上。 我创建了以下代码,但是我不断收到以下错误(很多错误)。该应用似乎陷入了循环: 以下是我使用的代码: 问题答案: 看起来您不小心在render方法中调用了该方法,而您可能想这样做。 如果您不想在onClick处理程序中创建lambda,我认为您将需要两个绑定方法

  • 我正在重写一些旧的ReactJS代码,但在修复此错误时遇到了麻烦(此错误在控制台中重复大约1700次,DOM根本不呈现): 警告:设置状态(…):无法在现有状态转换期间更新(例如在或其他组件的构造函数中)。渲染方法应该是道具和状态的纯函数;构造函数的副作用是一种反模式,但可以移动到。 我是一个组件,它将它的状态传递给一个应该呈现一些控件的组件。基于单击的控件,状态应该更改,并且应该呈现新的控件。

  • 无法在现有状态转换期间更新(例如在“呈现”中)。呈现方法应该是道具和状态的纯函数。 我如何修复这种情况,使它将加载项目,并单击链接将重新呈现表单?