构建一个模态组件,从应用程序的任何部分打开一个 Bootstrap 模态,然后在它的外部为该组件设置自定义状态。它工作正常,但我总是在打开模式后收到此错误,我似乎无法弄清楚原因:
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 tocomponentWillMount
.` Doesnt really break anything but error keeps showing up.
我的代码:
布局.js
import React from "react";
import {Link} from 'react-router';
import NotificationSystem from 'react-notification-system';
import AppHeader from "#/ui/header/AppHeader";
import AppFooter from "#/ui/footer/AppFooter";
import Modal from "#/ui/modals/modal/Modal";
import "@/main.scss";
import './layout.scss';
export default class Layout extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
app.notify.clear = this.refs.notificationSystem.clearNotifications;
app.notify = this.refs.notificationSystem.addNotification;
app.modal = this.refs.modal.updateProps;
}
render() {
return (
<div class="app">
<div class="header">
<AppHeader page={this.props.location.pathname.replace('/', '')}/>
</div>
<div class="body">
{this.props.children}
</div>
<div class="footer">
<AppFooter />
</div>
<NotificationSystem ref="notificationSystem" style={false} />
<Modal ref="modal" />
</div>
);
};
}
Modal.js
import React from "react";
import ReactDOM from 'react-dom';
import SVGInline from "react-svg-inline";
import {closeSvg} from '#/utils/Svg';
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
showHeader: true,
showFooter: false,
title: "",
size: '',
className: '',
id: '',
footerContent: null,
showSubmitBtn: true,
showCancelBtn: true,
cancelBtnText: "Cancel",
successBtnText: "Save Changes",
onModalClose: () => {},
showModal: false,
html: () => {}
}
this.updateProps = this.updateProps.bind(this);
this.hideModal = this.hideModal.bind(this);
}
componentWillMount() {
var self = this;
var $modal = $(ReactDOM.findDOMNode(this));
}
componentDidUpdate(prevProps, prevState) {
if(this.state.showModal) {
$('body').addClass('modal-open');
} else {
$('body').removeClass('modal-open');
}
}
componentWillUnmount() {
// $('body').removeClass("modal-open");
}
componentWillReceiveProps(nextProps) {
console.log(nextProps);
}
updateProps(args) {
let merged = {...this.state, ...args};
this.setState(merged);
}
hideModal() {
this.setState({
showModal: false
});
this.state.onModalClose();
}
buildFooter() {
if(this.props.footerContent) {
return (
<div class="content">
{this.props.footerContent}
</div>
)
} else if(this.props.showCancelBtn && this.props.showSubmitBtn) {
return (
<div class="buttons">
<button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>{this.props.cancelBtnText}</button>
<button type="button" class="btn btn-success">{this.props.successBtnText}</button>
</div>
);
} else if(this.props.showCancelBtn) {
return (<button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>Close</button>);
} else if(this.props.showSubmitBtn) {
return (<button type="button" class="btn btn-success">Save changes</button>);
}
}
render() {
let {
id,
className,
onModalClose,
size,
showHeader,
title,
children,
showFooter,
showModal,
html
} = this.state;
return (
<div class={`modal-wrapper`} >
{
showModal ?
<div class={`modal fade in ${className}`} role="dialog">
<div class="bg" ></div>
<div class={`modal-dialog ${size}`}>
<div class="modal-content">
{ showHeader ?
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<SVGInline svg={closeSvg} />
</button>
<h4 class="modal-title">{ title }</h4>
</div> : '' }
<div class="modal-body" >
{html()}
</div>
{ showFooter ?
<div class="modal-footer">
{ this.buildFooter() }
</div> : ''
}
</div>
</div>
</div>
: ''
}
</div>
);
}
}
选择默认图片.js
import React from "react";
import sass from "./selectdefaultimage.scss";
import FullScreenImageModal from "#/ui/modals/fullscreenimagemodal/FullScreenImageModal";
export default class SelectDefaultImage extends React.Component {
constructor() {
super();
this.state = {
showModal: false,
imgUrl: false,
}
}
showImageModal(image) {
this.setState({
showModal: true,
imgUrl: image
});
}
hideImageModal() {
this.setState({
showModal: false,
imgUrl: false
})
}
onSelectImageClick(e, image) {
$('.select-image-widget .active').removeClass('active');
$(e.target).parent().addClass('active');
// this.props.selectedImage(image)
}
render() {
let {listingManager, images, selectedImage} = this.props;
let {imgUrl} = this.state;
return (
<div class="content">
<div class="row">
<div class="col-sm-12">
<label class="control-label" for="description">Select an Image</label>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="select-image-widget">
{
images.map((image, idx) => {
return (
<div class="selecter" key={idx}>
<div class="img" style={{backgroundImage: `url(${listingManager.LISTINGS_PATH + image})` }} onClick={(e) => { this.onSelectImageClick(e, image) }}></div>
<i class="fa fa-search-plus" aria-hidden="true" onClick={()=> {this.showImageModal(image)}}></i>
</div>
)
})
}
</div>
</div>
</div>
{
this.state.showModal ?
app.modal({
showModal: true,
className: "fullscreen-image-modal",
size: "modal-lg",
html: () => {
return (<img src={listingManager.LISTINGS_PATH + imgUrl} />);
}
})
: ''
}
</div>
)
}
}
最佳答案
错误的原因很可能是在 SelectDefaultImage
中,您从 render 方法中调用了 app.modal
,而 app.modal
是 this.refs.modal.updateProps
,它执行 setState
。如果您将 app.modal
调用放在 showImageModal
中,我希望错误会消失。但是,通过 refs 和全局变量设置另一个组件的状态有点像 React 反模式,因此我建议进行一些重构并使用 props 来传递数据。
关于javascript - 在组件外部设置组件状态会导致错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46997118/