Posted at

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


目的

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 読み込み直したらエラーいっぱいになった