2017-10-29 67 views
3

构建一个模式组件,该组件从应用程序的任何部分打开引导模式,然后为该组件的外部设置自定义状态。它工作正常,但是当我打开模式,我似乎无法弄清楚我永远只是得到这个错误的原因:在组件外部设置组件状态会导致错误

警告:的setState(...):现有的状态转变(如内中无法更新render或另一个组件的构造函数)。渲染方法应该是道具和状态的纯粹功能;构造函数的副作用是一个反模式,但可以移动到componentWillMount .`不真正打破任何东西,但错误一直显示出来。

我的代码:

layout.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> 
     ); 
    } 
} 

SelectDefaultImage.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> 
     ) 
    } 
} 
+0

问题中的代码似乎没有任何可能导致上述错误的问题。你包括了一切吗?另一方面,由于您正在导入外部库,因此这个错误可能来自其中一个库。 –

+1

尽管不直接与问题相关,但尽量避免使用jquery进行反应。如果你认为你需要jQuery,那意味着你没有做出正确的反应。 https://reactjs.org/docs/thinking-in-react.html –

+0

@PubuduDodangoda只有当showModal设置为true时,错误才在Modal.js中。只有在模态显示后才会发生。我已包含与此问题相关的所有代码。我被困在自己身上,并且一直呆在现在4个小时...... – Shivam

回答

2

的错误的原因很可能是在SelectDefaultImage中,您从渲染方法中调用app.modal,并且app.modalthis.refs.modal.updateProps,它执行setState。如果您拨打showImageModal拨打app.modal,我预计该错误消失。但是,通过refs和globals设置另一个组件的状态有点像React反模式,所以我建议做一些重构并使用道具来传递数据。

+1

我其次。此外,你在这个州有职能。不推荐。 – sfratini

相关问题