Help us understand the problem. What is going on with this article?

react-dnd の tutorial を typescript mobx で写経した

More than 1 year has passed since last update.

目的

typescript と react-dnd と mobx を使う場合に、デコレータの組み合わせでどうなるか、を確認したかった。

経緯

mobx使ってる個人的なプロジェクトで、drag and drop したいかも。と思って、
react drag and drop でググってトップに出てきた react-dnd さんを確認してた

ドキュメント読んでて、デコレータ使ってた

mobx との相性問題とか出ないのかな。と気になったので

チュートリアル を写経ついでにmobx化

成果物

Tips

storeを参照したいreact-dndのデコレータに@injectつける

Chessboard.tsx
@inject("gameStore")
@DropTarget(
  ItemTypes.KNIGHT,
  BoardSquare.squareTarget,
  BoardSquare.dropCollector
)
class BoardSquare extends React.Component<

DropTargetに渡した squareTarget さんは、
BoardSquare を使う側で渡したpropsを使ってゴニョゴニョする。

Chessboard.tsx
@DropTarget(
  ItemTypes.KNIGHT,
  BoardSquare.squareTarget,
  BoardSquare.dropCollector
)
@inject("gameStore")
class BoardSquare extends React.Component<

この順だと、 squareTarget から gameStore を参照できない。

ちなみに squareTarget.drop だと第3引数に component が渡されてくる。
squareTarget.propsで頑張る方向もあるのかな。と思ってたのだけど、
canDrop を使い始めたところで第3引数が無くて死んだ。
DropTargetから見ると子となる、BoardSquareの状態を読むような形は作りとして微妙な感じがするので、
inject -> DropTarget で propsを引き継ぐのがきっと良いのだと納得することにした。

collector の型がpropsに渡されてくるので使いやすいように頑張る

react-dnd と mobx の組み合わせというより、react-dnd と typescript 的なTips

Chessboard.tsx
type OptionalPropertyNames<T> = { [K in keyof T]?: T[K] };
type OptionalReturnType<
  T extends (...args: any[]) => any
> = OptionalPropertyNames<ReturnType<T>>;

ReturnTypeだけだと以下のようなOptionalじゃない型が取れるので、

interface {
  connectDragSource: Function;
  connectDragPreview: Function;
  isDragging: Function;
}

使うところで上記のprops指定しないとエラーになってしまう。

それを抑制しつつ、中ではpropsとして使えるように、OptionalReturnType というものを拵えた。
(そもそも 2.8から入った ReturnType を知らなくて、これ便利と、大興奮。)
(別件で React.Component<P, S>P を使ってゴニョゴニョしてどこかで幸せになれないかな。と思ってる。)

細かい変更

source/collector を componentのstaticメソッドにしてみた

Chessboard.tsx
@DragSource(ItemTypes.KNIGHT, Knight.dragSource(), Knight.dragCollector)
class Knight extends React.Component<

操作なり状態について処理するときはstoreに任せるようにした

Chessboard.tsx
  static squareTarget = {
    canDrop(props, src) {
      return props.gameStore.canMoveKnight(props.x, props.y);
    },
    drop(props, src, component) {
      props.gameStore.moveKnight(props.x, props.y);
    }
  };

参考サイト

Appendix

  • codesandbox https://codesandbox.io/
    • 初めて使ったけど、結構使えるなー。と思った
    • 微妙に使いづらい所はあった
      • auto-reload でプレビューがエラーになる
      • 間違ってforkしちゃった
      • project 読み込み直したらエラーいっぱいになった
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした