sourcetip

전환이 포함된 리액트모달(에 추가)을 작성하려면 어떻게 해야 합니까?

fileupload 2023. 3. 9. 22:17
반응형

전환이 포함된 리액트모달(에 추가)을 작성하려면 어떻게 해야 합니까?

이 답변에는 https://stackoverflow.com/a/26789089/883571에 리액트 기반 모달(모달)을 추가함으로써 작성되는 모달(모달)이 있습니다.<body>하지만 React에서 제공하는 트랜지션 애드온과 호환되지 않습니다.

(진입 및 퇴출 중) 전환으로 작성하려면 어떻게 해야 합니까?

Ryan Florence는 react conf 2015에서 포털을 사용하는 것을 시연했습니다.다음은 심플을 작성하는 방법입니다.Portal컴포넌트...

var Portal = React.createClass({
  render: () => null,
  portalElement: null,
  componentDidMount() {
    var p = this.props.portalId && document.getElementById(this.props.portalId);
    if (!p) {
      var p = document.createElement('div');
      p.id = this.props.portalId;
      document.body.appendChild(p);
    }
    this.portalElement = p;
    this.componentDidUpdate();
  },
  componentWillUnmount() {
    document.body.removeChild(this.portalElement);
  },
  componentDidUpdate() {
    React.render(<div {...this.props}>{this.props.children}</div>, this.portalElement);
  }
});

리액트에서 보통 할 수 있는 건 포털 안에서 할 수 있는 건 다...

    <Portal className="DialogGroup">
       <ReactCSSTransitionGroup transitionName="Dialog-anim">
         { activeDialog === 1 && 
            <div key="0" className="Dialog">
              This is an animated dialog
            </div> }
       </ReactCSSTransitionGroup>
    </Portal> 

jsbin demo

라이언의 리액션 모델도 보실 수 있지만, 실제로 사용해 본 적이 없기 때문에 애니메이션과 잘 어울리는지 모르겠습니다.

도움이 될 만한 모듈 반응 포털을 작성했습니다.

사용방법:

import { Portal } from 'react-portal';
 
<Portal>
  This text is portaled at the end of document.body!
</Portal>
 
<Portal node={document && document.getElementById('san-francisco')}>
  This text is portaled into San Francisco!
</Portal>

반응 15.x

문서에서 설명하는 ES6 버전의 방법은 다음과 같습니다.

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

export default class BodyEnd extends React.PureComponent {
    
    static propTypes = {
        children: PropTypes.node,
    };
    
    componentDidMount() {
        this._popup = document.createElement('div');
        document.body.appendChild(this._popup);
        this._render();
    }

    componentDidUpdate() {
        this._render();
    }

    componentWillUnmount() {
        ReactDOM.unmountComponentAtNode(this._popup);
        document.body.removeChild(this._popup);
    }

    _render() {
        ReactDOM.render(this.props.children, this._popup);
    }
    
    render() {
        return null;
    }
}

DOM 의 마지막에 배치하고 싶은 요소를, 다음과 같이 정리합니다.

<BodyEnd><Tooltip pos={{x,y}}>{content}</Tooltip></BodyEnd>

리액트 16.x

다음은 React 16의 최신 버전입니다.

import React from 'react';
import ReactDOM from 'react-dom';

export default class BodyEnd extends React.Component {

    constructor(props) {
        super(props);
        this.el = document.createElement('div');
        this.el.style.display = 'contents';
        // The <div> is a necessary container for our
        // content, but it should not affect our layout.
        // Only works in some browsers, but generally
        // doesn't matter since this is at
        // the end anyway. Feel free to delete this line.
    }
    
    componentDidMount() {
        document.body.appendChild(this.el);
    }

    componentWillUnmount() {
        document.body.removeChild(this.el);
    }
    
    render() {
        return ReactDOM.createPortal(
            this.props.children,
            this.el,
        );
    }
}

작업 예

다른 답변에서 설명한 바와 같이 이 작업은 포털을 사용하여 수행할 수 있습니다.시작점v16.0 포털은 React에 포함되어 있습니다.

<body>
  <div id="root"></div>
  <div id="portal"></div>
</body>

보통 컴포넌트의 렌더 메서드에서 요소를 반환하면 가장 가까운 부모 노드의 자녀로 DOM에 마운트되지만 포털에서는 하위 요소를 DOM의 다른 위치에 삽입할 수 있습니다.

const PortalComponent = ({ children, onClose }) => {
  return createPortal(
    <div className="modal" style={modalStyle} onClick={onClose}>
      {children}
    </div>,
    // get outer DOM element
    document.getElementById("portal")
  );
};

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      modalOpen: false
    };
  }

  render() {
    return (
      <div style={styles}>
        <Hello name="CodeSandbox" />
        <h2>Start editing to see some magic happen {"\u2728"}</h2>
        <button onClick={() => this.setState({ modalOpen: true })}>
          Open modal
        </button>
        {this.state.modalOpen && (
          <PortalComponent onClose={() => this.setState({ modalOpen: false })}>
            <h1>This is modal content</h1>
          </PortalComponent>
        )}
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

여기서 작업 를 확인하십시오.

이 코드는 거의 자기 설명이며, 대부분의 사람들이 찾고 있는 핵심 솔루션을 망라하고 있습니다.

ReactDOM.render(
  <Modal />,
  document.body.appendChild( document.createElement( 'div' ) ),
)

여기서 근본적인 문제는 React에서는 부모에게만 컴포넌트를 마운트할 수 있다는 것입니다.이것은 항상 바람직한 동작은 아닙니다.하지만 이 문제에 어떻게 대처해야 할까요?

저는 이 문제를 해결하기 위해 해결책을 만들었습니다.자세한 문제의 정의, src 및 예는 https://github.com/fckt/react-layer-stack#rationale 에서 확인할 수 있습니다.

근거

react/react-dom에는, 다음의 2개의 기본적인 전제 조건/조건이 있습니다.

  • 모든 UI는 자연스럽게 계층화됩니다.이 때문에 우리는components서로 감싸고 있다
  • react-dom기본적으로 하위 구성 요소를 상위 DOM 노드에 마운트(물리적으로)

문제는 두 번째 자산이 경우에 따라서는 당신이 원하는 것이 아닐 수 있다는 것입니다.경우에 따라 구성 요소를 다른 물리적 DOM 노드에 마운트하고 상위 노드와 하위 노드 간의 논리적 연결을 동시에 유지할 수 있습니다.

인 예는 과 같은 컴포넌트입니다.에서는, 「Tooltip」의할 필요가 경우가 있습니다.개발 프로세스의 어느 시점에서 이 컴포넌트에 대한 설명을 추가해야 할 수 있습니다.UI element, 좌표를 ).UI element코디네이트 또는 마우스 좌표)와 동시에 정보가 필요합니다.정보가 지금 당장 표시되어야 하는지 여부, 콘텐츠 및 상위 컴포넌트의 컨텍스트가 필요합니다.이 예에서는 논리 계층이 물리적 DOM 계층과 일치하지 않을 수 있습니다.

질문에 대한 답변의 구체적인 예를 보려면 https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example을 참조하십시오.

import { Layer, LayerContext } from 'react-layer-stack'
// ... for each `object` in array of `objects`
  const modalId = 'DeleteObjectConfirmation' + objects[rowIndex].id
  return (
    <Cell {...props}>
        // the layer definition. The content will show up in the LayerStackMountPoint when `show(modalId)` be fired in LayerContext
        <Layer use={[objects[rowIndex], rowIndex]} id={modalId}> {({
            hideMe, // alias for `hide(modalId)`
            index } // useful to know to set zIndex, for example
            , e) => // access to the arguments (click event data in this example)
          <Modal onClick={ hideMe } zIndex={(index + 1) * 1000}>
            <ConfirmationDialog
              title={ 'Delete' }
              message={ "You're about to delete to " + '"' + objects[rowIndex].name + '"' }
              confirmButton={ <Button type="primary">DELETE</Button> }
              onConfirm={ this.handleDeleteObject.bind(this, objects[rowIndex].name, hideMe) } // hide after confirmation
              close={ hideMe } />
          </Modal> }
        </Layer>

        // this is the toggle for Layer with `id === modalId` can be defined everywhere in the components tree
        <LayerContext id={ modalId }> {({showMe}) => // showMe is alias for `show(modalId)`
          <div style={styles.iconOverlay} onClick={ (e) => showMe(e) }> // additional arguments can be passed (like event)
            <Icon type="trash" />
          </div> }
        </LayerContext>
    </Cell>)
// ...

나는 이것을 돕기 위해 도서관을 썼다.포털 전략에서 사용되는 DOM 삽입 해킹을 피하고 컨텍스트 기반 레지스트리를 사용하여 소스에서 타깃으로 컴포넌트를 전달합니다.

구현에서는 표준 React 렌더 사이클을 사용합니다.텔레포트/인젝트/트랜스포트하는 컴포넌트는 타겟에 이중 렌더 사이클을 발생시키지 않습니다.모든 것이 동시에 발생합니다.

API는 소스/타겟을 정의하기 위해 코드에서 마법 문자열을 사용하지 않도록 구성되었습니다.대신 대상(Injectionable) 및 원본(Injectionor)으로 사용할 구성요소를 명시적으로 작성하고 장식해야 합니다.이러한 종류의 일은 일반적으로 매우 마술적인 것으로 간주되기 때문에, 컴포넌트의 명시적인 표현(직접 Import 및 사용 필요)은 컴포넌트가 삽입되는 장소에 대한 혼란을 완화하는 데 도움이 될 수 있다고 생각합니다.

내 라이브러리에서 문서의 직계 하위 항목으로 렌더링할 수 없습니다.본문 구성 요소 트리의 루트 수준 구성 요소에 바인딩하여 허용 가능한 모달 효과를 얻을 수 있습니다.조만간 이 사용 사례의 예를 추가할 예정입니다.

상세한 것에 대하여는, https://github.com/ctrlplusb/react-injectables 를 참조해 주세요.

도움이 됐으면 좋겠다.위의 anwser에 근거한 이행모달의 현재 실장입니다.

  React = require 'react/addons'

  keyboard = require '../util/keyboard'
  mixinLayered = require '../mixin/layered'

  $ = React.DOM
  T = React.PropTypes
  cx = React.addons.classSet

  module.exports = React.createFactory React.createClass
    displayName: 'body-modal'
    mixins: [mixinLayered]

    propTypes:
      # this components accepts children
      name:             T.string.isRequired
      title:            T.string
      onCloseClick:     T.func.isRequired
      showCornerClose:  T.bool
      show:             T.bool.isRequired

    componentDidMount: ->
      window.addEventListener 'keydown', @onWindowKeydown

    componentWillUnmount: ->
      window.removeEventListener 'keydown', @onWindowKeydown

    onWindowKeydown: (event) ->
      if event.keyCode is keyboard.esc
        @onCloseClick()

    onCloseClick: ->
      @props.onCloseClick()

    onBackdropClick: (event) ->
      unless @props.showCornerClose
        if event.target is event.currentTarget
          @onCloseClick()

    renderLayer: ->
      className = "body-modal is-for-#{@props.name}"
      $.div className: className, onClick: @onBackdropClick,
        if @props.showCornerClose
          $.a className: 'icon icon-remove', onClick: @onCloseClick
        $.div className: 'box',
          if @props.title?
            $.div className: 'title',
              $.span className: 'name', @props.title
              $.span className: 'icon icon-remove', @onCloseClick
          @props.children

    render: ->
      $.div()

언급URL : https://stackoverflow.com/questions/28802179/how-to-create-a-react-modal-which-is-appended-to-body-with-transitions

반응형