警告:setState(...):在使用 redux/immutable 的现有状态转换期间无法更新 [英] Warning: setState(...): Cannot update during an existing state transition with redux/immutable

查看:68
本文介绍了警告:setState(...):在使用 redux/immutable 的现有状态转换期间无法更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到错误

<块引用>

警告:setState(...):无法在现有状态转换期间更新(例如在 render 或其他组件的构造函数中).Render 方法应该是 props 和 state 的纯函数;构造函数的副作用是一种反模式,但可以移至 componentWillMount.

我发现原因是

const mapStateToProps = (state) =>{返回 {通知: state.get("notifications").get("notifications").toJS()}}

如果我不返回通知,它就可以工作.但这是为什么呢?

从react-redux"导入{connect}从./actions"导入{removeNotification,deactivateNotification}从./Notifications.jsx"导入通知const mapStateToProps = (状态) =>{返回 {通知: state.get("notifications").get("notifications").toJS()}}const mapDispatchToProps = (调度) =>{返回 {关闭通知:(通知)=>{调度(停用通知(notification.id))setTimeout(() => dispatch(removeNotification(notification.id)), 2000)}}}const NotificationsBotBot = 连接(mapStateToProps,mapDispatchToProps)(通知)导出默认的 NotificationsBotBot从反应"导入反应类通知扩展了 React.Component {使成为() {返回 (<div></div>)}}导出默认通知

更新

在进一步调试中我发现,以上可能不是根本原因,我可以保留通知,但我需要删除 dispatch(push("/domains")) 我的重定向.

我是这样登录的:

export function doLogin (username, password) {返回函数(调度){调度(登录请求())console.log("模拟登录", 用户名, 密码)setTimeout(() => {调度(登录成功(`PLACEHOLDER_TOKEN${Date.now()}`))调度(添加通知({孩子们:成功登录",类型:接受",超时:2000,动作:好的"}))调度(推(/域"))}, 1000)}}

我发现调度导致警告,但为什么呢?我的域页面目前没有任何内容:

从react-redux"导入{connect}从./DomainsIndex.jsx"导入 DomainsIndex导出默认连接()(域索引)

域索引

导出默认类 DomainsIndex 扩展 React.Component {使成为() {返回 (<div><h1>域</h1>

)}}

更新 2

我的App.jsx. 是显示通知的内容

 <ConnectedRouter history={history}><布局><面板><开关><路由路径="/auth"/><路由组件={TopBar}/></开关><开关><路由精确路径="/" component={Index}/><Route path="/auth/login" component={LoginBotBot}/><AuthenticatedRoute 精确路径="/domains" component={DomainsPage}/><AuthenticatedRoute 精确路径="/domain/:id" component={DomainPage}/><路由组件={Http404}/></开关><通知/></面板></布局></ConnectedRouter></提供者>

解决方案

你的 dispatch(push('/domains')) 伴随着设置连接组件状态的其他调度(大概是一个关心通知)在 push 生效后重新安装/卸载.

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

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

如果可行,那么您可能需要重新考虑您的组件结构.我想 Notifications 是一个你想安装一次并在应用程序的生命周期内保持在那里的组件.尽量避免通过将它放在组件树中的更高位置来重新安装它,并使其成为 PureComponent(这里是 文档).此外,如果您的应用程序的复杂性增加,您应该考虑使用一个库来处理异步功能,例如 redux-传奇.

即使此警告通常是由于错误的操作调用而出现(例如在渲染时调用操作:onClick={action()} 而不是作为 lambda 传递:onClick={() => action()}),如果你的组件看起来像你提到的(只是渲染一个 div),那么这不是问题的原因.

I am getting the error

Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.

I found the cause to be

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

If I do not return notifications there it works. But why is that?

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

UPDATE

On further debugging I found that, the above may not be the root cause after all, I can have the notifications stay but I need to remove dispatch(push("/domains")) my redirect.

This is how I login:

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)
  }
}

I find that the dispatch causes the warning, but why? My domains page have nothing much currently:

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

export default connect()(DomainsIndex)

DomainsIndex

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

UPDATE 2

My App.jsx. <Notifications /> is what displays the notifications

  <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>

解决方案

Your dispatch(push('/domains')) comes along other dispatches that set the state for a connected component (presumably one that cares about notifications) that gets remounted/unmounted after the push takes effect.

As a workaround and proof of concept, try defering the dispatch(push('/domains')) call with a nested zero-second setTimeout. This should execute the push after any of the other actions finish (i.e. hopefully a render):

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

If that works, then you might want to reconsider your component structure. I suppose Notifications is a component you want to mount once and keep it there for the lifetime of the application. Try to avoid remounting it by placing it higher in the component tree, and making it a PureComponent (here are the docs). Also, if the complexity of your application increases, you should consider using a library to handle async functionality like redux-saga.

Even though this warning usually appears because of a misplaced action call (e.g. calling an action on render: onClick={action()} instead of passing as a lambda: onClick={() => action()}), if your components look like you've mentioned (just rendering a div), then that is not the cause of the problem.

这篇关于警告:setState(...):在使用 redux/immutable 的现有状态转换期间无法更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆