developer tip

React.js의 부트 스트랩 모달

copycodes 2021. 1. 5. 08:14
반응형

React.js의 부트 스트랩 모달


Bootstrap navbar 및 기타 위치의 버튼을 클릭하여 Bootstrap Modal을 열어야합니다 ( 구성 요소 인스턴스에 대한 데이터 표시, 즉 "편집"기능 제공 ).하지만이 작업을 수행하는 방법을 모르겠습니다. 내 코드는 다음과 같습니다.

편집 : 코드가 업데이트되었습니다.

ApplicationContainer = React.createClass({
    render: function() {
        return (
            <div className="container-fluid">
            <NavBar />
                <div className="row">
                    <div className="col-md-2">
                        <ScheduleEntryList />
                    </div>
                    <div className="col-md-10">
                    </div>
                </div>
                <ScheduleEntryModal />
            </div>
        );
    }
});

NavBar = React.createClass({
    render: function() {
        return (
            <nav className="navbar navbar-default navbar-fixed-top">
                <div className="container-fluid">
                    <div className="navbar-header">
                        <a className="navbar-brand" href="#">
                            <span className="glyphicon glyphicon-eye-open"></span>
                        </a>
                    </div>
                    <form className="navbar-form navbar-left">
                        <button className="btn btn-primary" type="button" data-toggle="modal" data-target="#scheduleentry-modal">
                            <span className="glyphicon glyphicon-plus">
                            </span>
                        </button>
                    </form>
                    <ul className="nav navbar-nav navbar-right">
                        <li><a href="#"><span className="glyphicon glyphicon-user"></span> Username</a></li>
                    </ul>
                </div>
            </nav>
        );
    }
});

ScheduleEntryList = React.createClass({
    getInitialState: function() {
        return {data: []}
    },

    loadData: function() {
        $.ajax({
            url: "/api/tasks",
            dataType: "json",

            success: function(data) {
                this.setState({data: data});
            }.bind(this),

            error: function(xhr, status, error) {
                console.error("/api/tasks", status, error.toString());
            }.bind(this)
        });
    },

    componentWillMount: function() {
        this.loadData();
        setInterval(this.loadData, 20000);
    },

    render: function() {
        items = this.state.data.map(function(item) {
            return <ScheduleEntryListItem item={item}></ScheduleEntryListItem>;
        });

        return (
            <div className="list-group">
                <a className="list-group-item active">
                    <h5 className="list-group-item-heading">Upcoming</h5>
                </a>
                {items}
            </div>
        );
    }
});

ScheduleEntryListItem = React.createClass({
    openModal: function() {
        $("#scheduleentry-modal").modal("show");
    },

    render: function() {
        deadline = moment(this.props.item.deadline).format("MMM Do YYYY, h:mm A");

        return (
            <a className="list-group-item" href="#" onClick={this.openModal}>
                <h5 className="list-group-item-heading">
                    {this.props.item.title}
                </h5>
                <small className="list-group-item-text">
                    {deadline}
                </small>
            </a>
        );
    }
});

Modal = React.createClass({
    componentDidMount: function() {
        $(this.getDOMNode())
            .modal({backdrop: "static", keyboard: true, show: false});
    },

    componentWillUnmount: function() {
        $(this.getDOMNode())
            .off("hidden", this.handleHidden);
    },

    open: function() {
        $(this.getDOMNode()).modal("show");
    },

    close: function() {
        $(this.getDOMNode()).modal("hide");
    },

    render: function() {
        return (
            <div id="scheduleentry-modal" className="modal fade" tabIndex="-1">
                <div className="modal-dialog">
                    <div className="modal-content">
                        <div className="modal-header">
                            <button type="button" className="close" data-dismiss="modal">
                                <span>&times;</span>
                            </button>
                            <h4 className="modal-title">{this.props.title}</h4>
                        </div>
                        <div className="modal-body">
                            {this.props.children}
                        </div>
                        <div className="modal-footer">
                            <button type="button" className="btn btn-danger pull-left" data-dismiss="modal">Delete</button>
                            <button type="button" className="btn btn-primary">Save</button>
                        </div>
                    </div>
                </div>
            </div>

        )
    }
});

ScheduleEntryModal = React.createClass({
    render: function() {
        var modal = null;
        modal = (
            <Modal title="Add Schedule Entry">
                    <form className="form-horizontal">
                        <div className="form-group">
                            <label htmlFor="title" className="col-sm-2 control-label">Title</label>
                            <div className="col-sm-10">
                                <input id="title" className="form-control" type="text" placeholder="Title" ref="title" name="title"/>
                            </div>
                        </div>
                        <div className="form-group">
                            <label htmlFor="deadline" className="col-sm-2 control-label">Deadline</label>
                            <div className="col-sm-10">
                                <input id="deadline" className="form-control" type="datetime-local" ref="deadline" name="deadline"/>
                            </div>
                        </div>
                        <div className="form-group">
                            <label htmlFor="completed" className="col-sm-2 control-label">Completed</label>
                            <div className="col-sm-10">
                                <input id="completed" className="form-control" type="checkbox" placeholder="completed" ref="completed" name="completed"/>
                            </div>
                        </div>
                        <div className="form-group">
                            <label htmlFor="description" className="col-sm-2 control-label">Description</label>
                            <div className="col-sm-10">
                                <textarea id="description" className="form-control" placeholder="Description" ref="description" name="description"/>
                            </div>
                        </div>
                    </form>
            </Modal>
        );

        return (
            <div className="scheduleentry-modal">
                {modal}
            </div>
        );
    }
});

코드에 대한 다른 의견 및 개선 사항에 감사드립니다.


React-Bootstrap ( https://react-bootstrap.github.io/components/modal )을 사용할 수 있습니다 . 해당 링크에 모달에 대한 예가 있습니다. react-bootstrap을로드하면 모달 구성 요소를 반응 구성 요소로 사용할 수 있습니다.

var Modal = ReactBootstrap.Modal;

그런 다음 반응 구성 요소로 <Modal/>.

Bootstrap 4의 경우 react-strap ( https://reactstrap.github.io )이 있습니다. React-Bootstrap은 Bootstrap 3 만 지원합니다.


나는 최근에 React-Bootstrap을 내 프로젝트에 추가하지 않고 이에 대한 좋은 해결책을 찾고있었습니다 (Bootstrap 4가 곧 출시 될 예정입니다).

이것은 내 솔루션입니다 : https://jsfiddle.net/16j1se1q/1/

let Modal = React.createClass({
    componentDidMount(){
        $(this.getDOMNode()).modal('show');
        $(this.getDOMNode()).on('hidden.bs.modal', this.props.handleHideModal);
    },
    render(){
        return (
          <div className="modal fade">
            <div className="modal-dialog">
              <div className="modal-content">
                <div className="modal-header">
                  <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                  <h4 className="modal-title">Modal title</h4>
                </div>
                <div className="modal-body">
                  <p>One fine body&hellip;</p>
                </div>
                <div className="modal-footer">
                  <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
                  <button type="button" className="btn btn-primary">Save changes</button>
                </div>
              </div>
            </div>
          </div>
        )
    },
    propTypes:{
        handleHideModal: React.PropTypes.func.isRequired
    }
});



let App = React.createClass({
    getInitialState(){
        return {view: {showModal: false}}
    },
    handleHideModal(){
        this.setState({view: {showModal: false}})
    },
    handleShowModal(){
        this.setState({view: {showModal: true}})
    },
    render(){
    return(
        <div className="row">
            <button className="btn btn-default btn-block" onClick={this.handleShowModal}>Open Modal</button>
            {this.state.view.showModal ? <Modal handleHideModal={this.handleHideModal}/> : null}
        </div>
    );
  }
});

React.render(
   <App />,
    document.getElementById('container')
);

주요 아이디어는 Modal 구성 요소가 표시 될 때만 React DOM으로 렌더링하는 것입니다 (앱 구성 요소 렌더링 기능에서). 모달이 현재 표시되는지 여부를 나타내는 '보기'상태를 유지합니다.

'componentDidMount'및 'componentWillUnmount'콜백은 Bootstrap 자바 스크립트 함수를 통해 모달 (React DOM으로 렌더링되면)을 숨기거나 표시합니다.

이 솔루션이 React 정신을 잘 따른다고 생각하지만 제안을 환영합니다!


getDOMNode()더 이상 사용되지 않습니다. 대신 refDOM 요소에 액세스 하는 데 사용하십시오 . 다음은 작동하는 모달 구성 요소 (Bootstrap 4)입니다. 상위 컴포넌트에 모달 컴포넌트를 표시할지 여부를 결정합니다.

예 : https://jsfiddle.net/sqfhkdcy/

class Modal extends Component {
    constructor(props) {
        super(props);
    }
    componentDidMount() {
        $(this.modal).modal('show');
        $(this.modal).on('hidden.bs.modal', handleModalCloseClick);
    }
    render() {
        return (
            <div>
                <div className="modal fade" ref={modal=> this.modal = modal} id="exampleModal" tabIndex="-1" role="dialog" aria- labelledby="exampleModalLabel" aria-hidden="true">
                    <div className="modal-dialog" role="document">
                        <div className="modal-content">
                            <div className="modal-header">
                                <h5 className="modal-title" id="exampleModalLabel">Modal title
                                </h5>
                                <button type="button" className="close" data- dismiss="modal" aria-label="Close">
                                    <span aria-hidden="true">&times;</span>
                                </button>
                            </div>
                            <div className="modal-body">
                                ...
                            </div>
                            <div className="modal-footer">
                                <button type="button" className="btn btn-secondary" data- dismiss="modal">Close</button>
                                <button type="button" className="btn btn-primary">Save changes</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

편집하다:

작동하는 데 필요한 가져 오기는 다음과 같습니다.

import $ from 'jquery';
window.jQuery = $;
window.$ = $;
global.jQuery = $;

이 기능을 만들었습니다.

onAddListItem: function () {
    var Modal = ReactBootstrap.Modal;
    React.render((
        <Modal title='Modal title' onRequestHide={this.hideListItem}>
            <ul class="list-group">
                <li class="list-group-item">Cras justo odio</li>
                <li class="list-group-item">Dapibus ac facilisis in</li>
                <li class="list-group-item">Morbi leo risus</li>
                <li class="list-group-item">Porta ac consectetur ac</li>
                <li class="list-group-item">Vestibulum at eros</li>
            </ul>
        </Modal>
    ), document.querySelector('#modal-wrapper'));
}

그런 다음 내 버튼 트리거에서 사용했습니다.

모달을 '숨기기':

hideListItem: function () {
    React.unmountComponentAtNode(document.querySelector('#modal-wrapper'));
},

솔루션과 같은 "reactstrap"을 달성하기 위해 부트 스트랩 cdn (css + js) 만 사용했습니다. 부모에서 자식 구성 요소로 동적 데이터를 전달하기 위해 props.children을 사용했습니다. 여기에서 자세한 내용을 확인할 수 있습니다 . 이런 식으로 모달 머리글, 모달 본문 및 모달 바닥 글 세 가지 개별 구성 요소가 있으며 서로 완전히 독립적입니다.


//Modal component
import React, { Component } from 'react';

export const ModalHeader = props => {
  return <div className="modal-header">{props.children}</div>;
};

export const ModalBody = props => {
  return <div className="modal-body">{props.children}</div>;
};

export const ModalFooter = props => {
  return <div className="modal-footer">{props.children}</div>;
};

class Modal extends Component {
  constructor(props) {
    super(props);
    this.state = {
      modalShow: '',
      display: 'none'
    };
    this.openModal = this.openModal.bind(this);
    this.closeModal = this.closeModal.bind(this);
  }

  openModal() {
    this.setState({
      modalShow: 'show',
      display: 'block'
    });
  }

  closeModal() {
    this.setState({
      modalShow: '',
      display: 'none'
    });
  }

  componentDidMount() {
    this.props.isOpen ? this.openModal() : this.closeModal();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.isOpen !== this.props.isOpen) {
      this.props.isOpen ? this.openModal() : this.closeModal();
    }
  }

  render() {
    return (
      <div
        className={'modal fade ' + this.state.modalShow}
        tabIndex="-1"
        role="dialog"
        aria-hidden="true"
        style={{ display: this.state.display }}
      >
        <div className="modal-dialog" role="document">
          <div className="modal-content">{this.props.children}</div>
        </div>
      </div>
    );
  }
}

export default Modal;

//App component
import React, { Component } from 'react';
import Modal, { ModalHeader, ModalBody, ModalFooter } from './components/Modal';

import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      modal: false
    };
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    this.setState({ modal: !this.state.modal });
  }

  render() {
    return (
      <div className="App">
        <h1>Bootstrap Components</h1>

        <button
          type="button"
          className="btn btn-secondary"
          onClick={this.toggle}
        >
          Modal
        </button>

        <Modal isOpen={this.state.modal}>
          <ModalHeader>
            <h3>This is modal header</h3>
            <button
              type="button"
              className="close"
              aria-label="Close"
              onClick={this.toggle}
            >
              <span aria-hidden="true">&times;</span>
            </button>
          </ModalHeader>
          <ModalBody>
            <p>This is modal body</p>
          </ModalBody>
          <ModalFooter>
            <button
              type="button"
              className="btn btn-secondary"
              onClick={this.toggle}
            >
              Close
            </button>
            <button
              type="button"
              className="btn btn-primary"
              onClick={this.toggle}
            >
              Save changes
            </button>
          </ModalFooter>
        </Modal>
      </div>
    );
  }
}

export default App;


이 모달을 시도해 볼 수 있습니다 : https://github.com/xue2han/react-dynamic-modal stateless이며 필요할 때만 렌더링 할 수 있으므로 사용하기가 매우 쉽습니다.

    class MyModal extends Component{
       render(){
          const { text } = this.props;
          return (
             <Modal
                onRequestClose={this.props.onRequestClose}
                openTimeoutMS={150}
                closeTimeoutMS={150}
                style={customStyle}>
                <h1>What you input : {text}</h1>
                <button onClick={ModalManager.close}>Close Modal</button>
             </Modal>
          );
       }
    }

    class App extends Component{
        openModal(){
           const text = this.refs.input.value;
           ModalManager.open(<MyModal text={text} onRequestClose={() => true}/>);
        }
        render(){
           return (
              <div>
                <div><input type="text" placeholder="input something" ref="input" /></div>
                <div><button type="button" onClick={this.openModal.bind(this)}>Open Modal </button> </div>
              </div>
           );
        }
    }

    ReactDOM.render(<App />,document.getElementById('main'));

특히 타사 라이브러리 (예 : React-Bootstrap)가 필요하지 않을 때 간단한 솔루션을 제공하는 @tgrrr 덕분입니다. 그러나이 솔루션에는 문제가 있습니다. 모달 컨테이너가 반응 구성 요소 내부에 포함되어 외부 반응 구성 요소 (또는 해당 부모 요소)가 위치 스타일이 고정 / 상대 / 절대 일 때 모달 언더 백그라운드 문제가 발생합니다. 이 문제를 만났고 새로운 해결책을 찾았습니다.

"use strict";

var React = require('react');
var ReactDOM = require('react-dom');

var SampleModal = React.createClass({
  render: function() {
    return (
      <div className="modal fade" tabindex="-1" role="dialog">
        <div className="modal-dialog">
          <div className="modal-content">
            <div className="modal-header">
              <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
              <h4 className="modal-title">Title</h4>
            </div>
            <div className="modal-body">
              <p>Modal content</p>
            </div>
            <div className="modal-footer">
              <button type="button" className="btn btn-default" data-dismiss="modal">Cancel</button>
              <button type="button" className="btn btn-primary">OK</button>
            </div>
          </div>
        </div>
      </div>
    );
  }
});

var sampleModalId = 'sample-modal-container';
var SampleApp = React.createClass({
  handleShowSampleModal: function() {
    var modal = React.cloneElement(<SampleModal></SampleModal>);
    var modalContainer = document.createElement('div');
    modalContainer.id = sampleModalId;
    document.body.appendChild(modalContainer);
    ReactDOM.render(modal, modalContainer, function() {
      var modalObj = $('#'+sampleModalId+'>.modal');
      modalObj.modal('show');
      modalObj.on('hidden.bs.modal', this.handleHideSampleModal);
    }.bind(this));
  },
  handleHideSampleModal: function() {
    $('#'+sampleModalId).remove();
  },
  render: function(){    
    return (
      <div>
        <a href="javascript:;" onClick={this.handleShowSampleModal}>show modal</a>
      </div>
    )
  }
});

module.exports = SampleApp;

주요 아이디어는 다음과 같습니다.

  1. 모달 요소 (ReactElement 객체)를 복제합니다.
  2. div 요소를 만들고 문서 본문에 삽입합니다.
  3. 새로 삽입 된 div 요소에서 복제 된 모달 요소를 렌더링합니다.
  4. When the render is finished, show modal. Also, attach an event listener, so that when modal is hidden, the newly inserted div element will be removed.

Reactstrap also has an implementation of Bootstrap Modals in React. This library targets Bootstrap version 4, whereas react-bootstrap targets version 3.X.


Just add href='#scheduleentry-modal' to the element you want to open the modal with

Or using jQuery: $('#scheduleentry-modal').modal('show');

ReferenceURL : https://stackoverflow.com/questions/28241912/bootstrap-modal-in-react-js

반응형