React-dnd: μž‘νžˆμ§€ μ•Šμ€ 였λ₯˜: λ™μ‹œμ— 두 개의 HTML5 λ°±μ—”λ“œλ₯Ό κ°€μ§ˆ 수 μ—†μŠ΅λ‹ˆλ‹€.

에 λ§Œλ“  2017λ…„ 04μ›” 20일  Β·  3μ½”λ©˜νŠΈ  Β·  좜처: react-dnd/react-dnd

Rails5, action Cable, React and Rails, React DnD둜 POCλ₯Ό λ§Œλ“€λ €κ³  ν•©λ‹ˆλ‹€.

λͺ©μ μ€ trello와 같은 앱을 λ§Œλ“œλŠ” κ²ƒμ΄μ§€λ§Œ λͺ¨μ§‘ ν”„λ‘œμ„ΈμŠ€λ₯Ό μœ„ν•œ κ²ƒμž…λ‹ˆλ‹€.

λ‚΄ 전면은 ReactJS에 μžˆμŠ΅λ‹ˆλ‹€.

3개의 ꡬ성 μš”μ†Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. λ¨Όμ € μ»¨ν…Œμ΄λ„ˆλŠ” "Candidates"λ₯Ό ν˜ΈμΆœν•˜κ³  이 ꡬ성 μš”μ†ŒλŠ” "Card" ꡬ성 μš”μ†Œλ₯Ό ν˜ΈμΆœν•˜λŠ” 2개의 "CardBoard" ꡬ성 μš”μ†Œλ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€.

λ“œλž˜κ·Έ κ°€λŠ₯ν•œ μΉ΄λ“œ 및 놓기 κ°€λŠ₯ν•œ CardBoard에 λŒ€ν•΄ μ‚¬μš©μžκ°€ DnD λΌμ΄λΈŒλŸ¬λ¦¬μ— λ°˜μ‘ν•©λ‹ˆλ‹€. μΉ΄λ“œλ³΄λ“œμ— μΉ΄λ“œλ₯Ό λ–¨μ–΄λœ¨λ¦΄ λ•Œ λ‚΄ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•˜κΈ° μœ„ν•΄ 포슀트 콜과 μ›Ή μ†ŒμΌ“(rails5의 μ•‘μ…˜ 케이블)을 μ‚¬μš©ν•©λ‹ˆλ‹€. 톡화 ν›„ λ‹€μŒκ³Ό 같은 λ©”μ‹œμ§€κ°€ ν‘œμ‹œλ˜λŠ” 이유λ₯Ό 이해할 수 μ—†μŠ΅λ‹ˆλ‹€.

Uncaught Error: Cannot have two HTML5 backends at the same time.
    at HTML5Backend.setup (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:4175), <anonymous>:87:15)
    at DragDropManager.handleRefCountChange (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:3566), <anonymous>:52:22)
    at Object.dispatch (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:4931), <anonymous>:186:19)
    at HandlerRegistry.addSource (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:3594), <anonymous>:104:18)
    at registerSource (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:4294), <anonymous>:9:27)
    at DragDropContainer.receiveType (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:1793), <anonymous>:146:32)
    at DragDropContainer.receiveProps (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:1793), <anonymous>:135:14)
    at new DragDropContainer (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:1793), <anonymous>:102:13)
    at eval (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:4399), <anonymous>:295:18)
    at measureLifeCyclePerf (eval at <anonymous> (webpack-bundle.self-7b1a342….js?body=1:4399), <anonymous>:75:12)

ν›„λ³΄μž.jsx =

import React, { PropTypes } from 'react';
import { DragDropContextProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import CardBoard from './CardBoard.jsx';

export default class Candidates extends React.Component {

  constructor(props, _railsContext) {
    super(props);

    this.state = {
      candidates: this.props.candidates
    }

    this.filterByStatus = this.filterByStatus.bind(this)
  }

  componentDidMount() {
    this.setupSubscription();
  }

  setupSubscription() {
    App.candidate = App.cable.subscriptions.create("CandidateChannel", {
      connected: () => {
        console.log("User connected !")
      },

      received: (data) => {
        this.setState({ candidates: data.candidates })
      },
    });
   }

  render() {
    return (
      <DragDropContextProvider backend={HTML5Backend}>
        <div className="recruitment">
          {
            ["Γ€ Rencontrer", "Entretien"].map((status, index) => {
              return (
                <CardBoard candidates={(this.filterByStatus({status}))} status={status} key={index} />
              );
            })
          }
        </div>
      </DragDropContextProvider>
    );
  } 
}

μΉ΄λ“œλ³΄λ“œ.jsx =

import React, { PropTypes } from 'react';
import Card from './Card.jsx';
import { DropTarget } from 'react-dnd';
import ItemTypes from './ItemTypes';

const cardTarget = {
  drop(props: Props) {
    var status = ''

    if(props.status == "Γ€ Rencontrer") {
      status = 'to_book'
    } else {
      status = 'interview'
    }

    return { status: status };
  },
};

@DropTarget(ItemTypes.CARD, cardTarget, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver(),
  canDrop: monitor.canDrop(),
}))

export default class CardBoard extends React.Component<Props> {

  constructor(props, _railsContext) {
    super(props);
  }

  render() {
    const { canDrop, isOver, connectDropTarget } = this.props;
    const isActive = canDrop && isOver;


    return connectDropTarget(
      <div className={`${this.props.status} ui cards`}>
        <h2>{`${this.props.status} (${this.props.candidates.length})`}</h2>
        {
          (this.props.candidates).map((candidate, index) => {
            return <Card candidate={candidate} key={index} />
          })
        }
        { isActive?
          'Release to drop' : 'drag a card here'
        }
      </div>
    );
  }
}

μΉ΄λ“œ.jsx=

import React, { PropTypes } from 'react';
import { DragSource } from 'react-dnd';
import ItemTypes from './ItemTypes';


const cardSource = {
  beginDrag(props) {
    return {
      candidate_id: props.candidate.id,
    };
  },

  endDrag(props, monitor) {
    const item = monitor.getItem();
    const dropResult = monitor.getDropResult();

    if (dropResult) {
      console.log(`You dropped ${item.candidate_id} vers ${dropResult.status} !`);
      $.post(`/update_status/${item.candidate_id}/${dropResult.status}`);
    }
  },
};

@DragSource(ItemTypes.CARD, cardSource, (connect, monitor) => ({
  connectDragSource: connect.dragSource(),
  isDragging: monitor.isDragging(),
}))

export default class Card extends React.Component {

  constructor(props, _railsContext) {
    super(props);
  }

  render() {
    const { isDragging, connectDragSource } = this.props;
    const { name } = this.props;
    const opacity = isDragging ? 0 : 1;

    var candidate = this.props.candidate;

    return (
      connectDragSource(
        <div className="card" key={candidate.id} style={{opacity}}>
          <div className="content">
            <div className="header">{`${candidate.first_name} ${candidate.last_name}`}</div>
            <div className="description">
              {candidate.job_title}
            </div>
            <span className="right floated">
              <i className="heart outline like icon"></i>
              {candidate.average_rate}
            </span>
          </div>
        </div>
      )
    );
  }
}

더 λ‚˜μ€ 이해λ₯Ό μœ„ν•΄ μ—¬κΈ° λ‚΄ κΈ°λŠ₯κ³Ό λ²„κ·Έμ˜ gifκ°€ μžˆμŠ΅λ‹ˆλ‹€.
bugcard

wontfix

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

@antoineBernard μ΅œκ·Όμ— 같은 였λ₯˜λ₯Ό κ·Ήλ³΅ν•˜λ €κ³  ν•˜λ£¨ 쒅일 λ³΄λƒˆμŠ΅λ‹ˆλ‹€. ν™•μ‹€ν•˜μ§€ μ•Šμ§€λ§Œ κ·€ν•˜μ™€ λΉ„μŠ·ν•œ 문제일 수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒ 2가지 쀑 ν•˜λ‚˜λ₯Ό μ‹œλ„ν•΄ λ³΄μ„Έμš”.

  1. <DragDropContextProvider> λ₯Ό Candidates.jsx 의 μƒμœ„ κ΅¬μ„±μš”μ†Œλ‘œ 이동해 λ³΄μ‹­μ‹œμ˜€.
  2. 싱글톀 νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ—¬ DragDropContext 의 단일 μΈμŠ€ν„΄μŠ€λ§Œ μ•± μ „μ²΄μ—μ„œ μ΄ˆκΈ°ν™”λ˜λ„λ‘ ν•©λ‹ˆλ‹€. @gcorne 의 μ œμ•ˆ 을 μ„±κ³΅μ μœΌλ‘œ μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

λ‹Ήμ‹ μ—κ²Œλ„ νš¨κ³Όκ°€ 있기λ₯Ό λ°”λžλ‹ˆλ‹€!

λͺ¨λ“  3 λŒ“κΈ€

@antoineBernard μ΅œκ·Όμ— 같은 였λ₯˜λ₯Ό κ·Ήλ³΅ν•˜λ €κ³  ν•˜λ£¨ 쒅일 λ³΄λƒˆμŠ΅λ‹ˆλ‹€. ν™•μ‹€ν•˜μ§€ μ•Šμ§€λ§Œ κ·€ν•˜μ™€ λΉ„μŠ·ν•œ 문제일 수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒ 2가지 쀑 ν•˜λ‚˜λ₯Ό μ‹œλ„ν•΄ λ³΄μ„Έμš”.

  1. <DragDropContextProvider> λ₯Ό Candidates.jsx 의 μƒμœ„ κ΅¬μ„±μš”μ†Œλ‘œ 이동해 λ³΄μ‹­μ‹œμ˜€.
  2. 싱글톀 νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ—¬ DragDropContext 의 단일 μΈμŠ€ν„΄μŠ€λ§Œ μ•± μ „μ²΄μ—μ„œ μ΄ˆκΈ°ν™”λ˜λ„λ‘ ν•©λ‹ˆλ‹€. @gcorne 의 μ œμ•ˆ 을 μ„±κ³΅μ μœΌλ‘œ μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

λ‹Ήμ‹ μ—κ²Œλ„ νš¨κ³Όκ°€ 있기λ₯Ό λ°”λžλ‹ˆλ‹€!

이것은 λ‚˜λ₯Ό μœ„ν•΄ μΌν–ˆμŠ΅λ‹ˆλ‹€ : https://github.com/react-dnd/react-dnd/issues/186#issuecomment -282789420

이 λ¬Έμ œλŠ” 졜근 ν™œλ™μ΄ μ—†μ—ˆκΈ° λ•Œλ¬Έμ— μžλ™μœΌλ‘œ 였래된 κ²ƒμœΌλ‘œ ν‘œμ‹œλ˜μ—ˆμŠ΅λ‹ˆλ‹€. 더 이상 ν™œλ™μ΄ μ—†μœΌλ©΄ νμ‡„λ©λ‹ˆλ‹€. κ·€ν•˜μ˜ 기여에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰