APIがエラーを返したときにアラートを表示しようとしています。警告ウィンドウには、sweetalert2を使用しています。私のrenderメソッドでは、エラーメッセージにコンテンツが含まれているかどうかを確認しています。エラーメッセージが含まれている場合、ユーザーにアラートを表示します。
フォームを送信するときに、API呼び出しを行います。エラーが返された場合、レデューサーはストア(状態)を変更し、ページを再度レンダリングします。
以下の行を追加したので、エラーが発生し続けます。
{saveLabelFetchError && this.toggleAlertFailure(saveLabelFetchError)}
エラー:
index.js:1375警告:unstable_flushDiscreteUpdates:Reactが既にレンダリングされている場合、更新をフラッシュできません。
私のコンポーネント:
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);
コンソールにこのエラーメッセージが表示され続ける理由を教えてください。
{saveLabelFetchError && this.toggleAlertFailure(saveLabelFetchError)}
レンダーサイクルの前、つまりコンポーネントがマウントされる前にdomを更新しようとしています。したがって、エラーが発生します。
理想的には、(react
APIを介さずに)domを直接変更するライブラリをreact libと一緒に使用しないでください。詳しくは こちら をご覧ください。
解決策は、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);
sweetalert2の反応ラッパー も確認できます。