2017-10-29 12 views
3

アプリケーションの任意の部分からブートストラップモーダルを開き、外部のコンポーネントのカスタム状態を設定するモーダルコンポーネントを構築します。正常に動作しますが、私はモーダルを開くと常にこのエラーが発生します。理由はわかりません:コンポーネント外のコンポーネント状態を設定すると、エラーが発生する

警告:setState(...):既存の状態遷移中には更新できませんrenderまたは別のコンポーネントのコンストラクタ)。レンダリング方法は、小道具と州の純粋な機能でなければなりません。コンストラクタの副作用はアンチパターンですが、componentWillMountに移動することができます。 `doesntは本当に何かを壊しますが、エラーは表示され続けます。

マイコード:

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つが原因で発生している可能性があります。 –

+1

そして、直接質問には関係しませんが、反応とjqueryの使用を避けるようにしてください。 jqueryが必要だと思うなら、それはあなたが正しい方法で反応していないことを意味します。 https://reactjs.org/docs/thinking-in-react.html –

+0

@ PubuduDodangoda showModalがtrueに設定されている場合のみ、Modal.jsにエラーがあります。モーダルが表示された後にのみ発生します。 Iveには、この問題に関連するすべてのコードが含まれています。私は自分で立ち往生していて、今は4時間ぐらいです。 – Shivam

答えて

2

エラーの理由は、SelectDefaultImageでは、レンダリングメソッドからapp.modalを呼び出し、app.modalthis.refs.modal.updatePropsとなり、setStateとなります。 app.modalコールをshowImageModalに置くと、エラーが消えてしまいます。しかし、refとグローバルで別のコンポーネントの状態を設定するのは少し反作用パターンなので、リファクタリングとプロップを使ってデータを渡すことをお勧めします。

+1

私はこれをもう一度。また、あなたは州の機能を持っています。どちらもお勧めしません。 – sfratini

関連する問題