Javascript 当 React 已经在渲染时无法刷新更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/58040892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:19:44  来源:igfitidea点击:

Cannot flush updates when React is already rendering

javascriptreactjssweetalert

提问by J. Adam

I'm trying to show an alert when the API returns an error. For the alert window I'm using sweetalert2. In my render method I'm checking if the error message contains content. If it contains an error message I want to show the user an alert.

我试图在 API 返回错误时显示警报。对于警报窗口,我使用的是 sweetalert2。在我的渲染方法中,我正在检查错误消息是否包含内容。如果它包含错误消息,我想向用户显示警报。

When I submit the form, I make an API call. If it returns an error the reducer changes the store (state) and it renders the page again.

当我提交表单时,我进行了 API 调用。如果它返回错误,reducer 会更改存储(状态)并再次呈现页面。

Since I added the line below, I keep getting an error:

由于我添加了下面的行,我不断收到错误消息:

{saveLabelFetchError && this.toggleAlertFailure(saveLabelFetchError)}

error:

错误:

index.js:1375 Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.

index.js:1375 警告:unstable_flushDiscreteUpdates:当 React 已经在渲染时无法刷新更新。

My component:

我的组件:

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";

import { saveLabelValueRequest } from "../../actions/labels";

import Swal from "sweetalert2";
import "./styles.css";
import Button from "@kof/button";

export class NewLabels extends Component {
  state = {
    labelInput: ""
  };

  inputChangedhandler = e => {
    this.setState({ labelInput: e.target.value });
  };

  toggleAlertFailure = message => {
    Swal.fire({
      type: "error",
      title: "Oops...",
      text: message
    });
  };

  saveLabel = event => {
    event.persist();
    event.preventDefault();
    Swal.fire({
      title: "Are you sure?",
      text: "You won't be able to revert this!",
      type: "warning",
      showCancelButton: true,
      confirmButtonColor: "#3085d6",
      cancelButtonColor: "#d33",
      confirmButtonText: "Yes, save it."
    }).then(result => {
      if (result.value) {
        const labelKeyUuid = this.props.labelKey.uuid;
        const labels = event.target.elements.labels.value;
        this.props.saveLabelValue(labelKeyUuid, labels);
      }
    });
  };

  render() {
    const { load, saveLabelFetchError } = this.props;
    return (
      <div>
        <form onSubmit={this.saveLabel}>
          <textarea onChange={this.inputChangedhandler}></textarea>
          <textarea></textarea>
          <Button onClick={() => load(this.state.labelInput)}>Preview</Button>
          <Button type="submit">Save</Button>
        </form>
        {saveLabelFetchError && this.toggleAlertFailure(saveLabelFetchError)}
      </div>
    );
  }
}

NewLabels.propTypes = {
  saveLabelFetchError: PropTypes.string,
  isFetching: PropTypes.bool,
  labelKey: PropTypes.object,
  saveLabelValue: PropTypes.func
};

NewLabels.defaultProps = {
  saveLabelFetchError: "",
  labelKey: {},
  isFetching: false,
  saveLabelValue: () => {}
};

export default connect(
  state => ({
    saveLabelFetchError: state.labelsStore.saveLabelError,
    isFetching: state.labelsStore.isFetching,
    labelKey: state.labelsStore.labelKey
  }),
  dispatch =>
    bindActionCreators(
      {
        saveLabelValue: saveLabelValueRequest
      },
      dispatch
    )
)(NewLabels);

I would like to know why i keep getting this error message in my console.

我想知道为什么我的控制台中不断收到此错误消息。

回答by Abhishek

{saveLabelFetchError && this.toggleAlertFailure(saveLabelFetchError)}

You are trying to update the dom before render cycle i.e before component has mounted. hence, you are getting an error.

您正在尝试在渲染周期之前更新 dom,即在组件安装之前。因此,您收到错误消息。

Ideally, you should avoid using any library that mutates dom directly (not via reactAPIs) with react lib. You can read more from here

理想情况下,您应该避免使用任何通过reactreact lib直接(而不是通过API)改变 dom 的库。你可以从这里阅读更多

The solution is to check if there is a change in props value, if so then show error popup. And also make sure we are not mutating dom during react's render cycle.

解决方案是检查 props 值是否有变化,如果有则显示错误弹出窗口。还要确保我们不会在 react 的渲染周期中改变 dom。


import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";

import { saveLabelValueRequest } from "../../actions/labels";

import Swal from "sweetalert2";
import "./styles.css";
import Button from "@kof/button";

export class NewLabels extends Component {
  state = {
    labelInput: "",
    prevSaveLabelFetchError: ""
  };

  static getDerivedStateFromProps(props, state) {
    if (props.saveLabelFetchError !== state.prevSaveLabelFetchError) {
      this.toggleAlertFailure(props.saveLabelFetchError);
      return {
        prevSaveLabelFetchError: props.saveLabelFetchError
      };
    }
    return null;
  }

  inputChangedhandler = e => {
    this.setState({ labelInput: e.target.value });
  };

  toggleAlertFailure = message => {
    Swal.fire({
      type: "error",
      title: "Oops...",
      text: message
    });
  };

  saveLabel = event => {
    event.persist();
    event.preventDefault();
    Swal.fire({
      title: "Are you sure?",
      text: "You won't be able to revert this!",
      type: "warning",
      showCancelButton: true,
      confirmButtonColor: "#3085d6",
      cancelButtonColor: "#d33",
      confirmButtonText: "Yes, save it."
    }).then(result => {
      if (result.value) {
        const labelKeyUuid = this.props.labelKey.uuid;
        const labels = event.target.elements.labels.value;
        this.props.saveLabelValue(labelKeyUuid, labels);
      }
    });
  };

  render() {
    const { load } = this.props;
    return (
      <div>
        <form onSubmit={this.saveLabel}>
          <textarea onChange={this.inputChangedhandler}></textarea>
          <textarea></textarea>
          <Button onClick={() => load(this.state.labelInput)}>Preview</Button>
          <Button type="submit">Save</Button>
        </form>
      </div>
    );
  }
}

NewLabels.propTypes = {
  saveLabelFetchError: PropTypes.string,
  isFetching: PropTypes.bool,
  labelKey: PropTypes.object,
  saveLabelValue: PropTypes.func
};

NewLabels.defaultProps = {
  saveLabelFetchError: "",
  labelKey: {},
  isFetching: false,
  saveLabelValue: () => {}
};

export default connect(
  state => ({
    saveLabelFetchError: state.labelsStore.saveLabelError,
    isFetching: state.labelsStore.isFetching,
    labelKey: state.labelsStore.labelKey
  }),
  dispatch =>
    bindActionCreators(
      {
        saveLabelValue: saveLabelValueRequest
      },
      dispatch
    )
)(NewLabels);


You can also look at react wrapper for sweetalert2

您还可以查看sweetalert2 的反应包装器