6

Rails5、action Cable、React and Rails、React DnD で POC を作成しようとしています。

目的は、trello のようなアプリを作成することですが、採用プロセス用です。

私のフロントはReactJSにあります。

私は 3 つのコンポーネントを持っています。まず、「Candidates」というコンテナを呼び出します。このコンポーネントは、「Card」コンポーネントを呼び出す 2 つの「CardBoard」コンポーネントを呼び出します。

私は、ドラッグ可能なカードとドロップ可能な CardBoard の DnD ライブラリに反応します。カードをボール紙に落とすと、post 呼び出しと websocket (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)

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

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

Card.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 をここに示します。

ここにすべてのコードを含む私のgithubリポジトリ

4

5 に答える 5

0

DragDropContext新しいファイルを作成して、必要な場所にインポートできます。

import HTML5 from 'react-dnd-html5-backend';
import {DragDropContext} from 'react-dnd';
export default DragDropContext(HTML5);

ソース: https://github.com/react-dnd/react-dnd/issues/708#issuecomment-309259695

またはフックを使用する:

import { DndProvider, createDndContext } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import React, { useRef } from "react";

const RNDContext = createDndContext(HTML5Backend);

function useDNDProviderElement(props) {
  const manager = useRef(RNDContext);

  if (!props.children) return null;

  return <DndProvider manager={manager.current.dragDropManager}>{props.children}</DndProvider>;
}

export default function DragAndDrop(props) {
  const DNDElement = useDNDProviderElement(props);
  return <React.Fragment>{DNDElement}</React.Fragment>;
}

使用する:

import DragAndDrop from "../some/path/DragAndDrop";

export default function MyComp(props){
   return <DragAndDrop>....<DragAndDrop/>
}

ソース: https://github.com/react-dnd/react-dnd/issues/186#issuecomment-561631584

使用する場合はBrowserRouter、次の場所から移動しDragDropContextProviderますBrowserRouter

ソース: https://github.com/react-dnd/react-dnd/issues/186#issuecomment-453990887

于 2020-11-05T13:08:54.197 に答える