75549


# やりたいこと

12種の画像をドラッグアンドドロップで動かせるようにすることです。その各画像の位置を状態として保存することで、コンポーネントが再描画されても動かした位置に画像があるようにしたいです。  
各画像は色が違うので`color`という変数で識別しています。

# 困っていること

画像のドラッグ時に動く関数に、デフォルトで渡ってくる引数を保持したまま渡したい変数（`color`）を渡せないことです（それにより、どの画像を動かしているかの情報を判別できず、上記「やりたいこと」の実現ができないです）。

自分の中での既知の方法で渡したい変数（`color`）を引数として指定すると、ドラッグ時に働く`onDrag`オプションでデフォルトで渡せるはずの`e`と`data`が渡せなくなってしまいます。そこで今度は`color`を指定しないと、当たり前ですが、`color`が情報として渡ってきません…。

おそらくJavaScriptの仕様の理解の部分だと思うのですが…検索力等足りずに質問に至りました。

コードは下記「コード」、ドラッグアンドドロップで使っているライブラリ「react-draggable」は下記「参考文献」よりご確認いただけます。

# 教えていただきたいこと

  1. ドラッグ時に動く`handleDrag()`にどの画像を操作しているかの情報である`color`を渡しつつ、デフォルトで入ってくる`e`と`data`も受け取れるような書き方。
  2. もしくは、根本的にやりかたが間違っている場合はそのご指摘と正攻法。

# 主な利用技術・環境

[code]

      "dependencies": {
        "react": "17.0.1",
        "react-dom": "17.0.1",
        "react-draggable": "^4.4.3",
      },
    
[/code]

# コード

**Map.jsx**

[code]

    // インポート等、省略
    
      const playerColorImageList = {
          red: Red,
          // 中略
          lime: Lime
        };
    
      const playerColorList = Object.keys(playerColorImageList);
    
      const [playerIconPosition, setPlayerIconPosition] = React.useState({
        red: {
          x: 0,
          y: 0,
        },
        // 中略
        lime: {
          x: 0,
          y: 0,
        },
      });
        
       // この関数でcolorとdataを使いたいが、両方利用できるような書き方がわからない。
        const handleDrag = (e, data, color) => {
    
        console.log('start');
        console.log(e);
        console.log(data);
        // console.log(color);
        console.log('end');
    
        // setPlayerIconPosition({...playerIconPosition,
        //   [color]: {
        //     x: data.x,
        //     y: data.y,
        //   }
        // });
    
    
      };
    
      const playersIcon = playerColorList.map((color) => 
        
        <Grid item xs={1}>  
          <Draggable
            position={playerIconPosition[color]}
            onDrag={handleDrag} // 記述①
           // onDrag={handleDrag(color)}  記述②
          >
            <img src={playerColorImageList[color]} className={classes.img}/>
          </Draggable>    
        </Grid>
        );
    
    
      return (
    
      <Grid container xs={12} alignItems="center" justify="center">
        {playersIcon}
      </Grid>          
    
      );
    
[/code]

# 動作

**記述①のときのコンソールの一部**

[code]

    start Map.jsx:124
    TouchEvent {isTrusted: true, touches: TouchList, targetTouches: TouchList, changedTouches: TouchList, altKey: false, …}
     Map.jsx:125
    {node: img.Map-img-66.react-draggable.react-draggable-dragging.react-draggable-dragged, x: 44.56512451171875, y: -33.11798095703125, deltaX: 1.40960693359375, deltaY: -0.83770751953125, …} Map.jsx:126
    end Map.jsx:127
    
[/code]

`data`と`e`は取得できますが、colorを取得できません。

**記述②のときのコンソールの一部**

[code]

    start Map.jsx:124
    red Map.jsx:125
    undefined Map.jsx:126
    end Map.jsx:127
    
[/code]

今後は変数`e`に`color`の値が入ってきてしまい、こちらも値を取りたいように取れません。

# 参考文献

  1. [react-draggable](https://github.com/react-grid-layout/react-draggable)

用語等の把握不足で分かりづらい説明になっているかとおもわれます。申し訳ありません。  
ご教授お願い申し上げます。

teratailでも同様の質問を投稿しています。  
<https://teratail.com/questions/335459>


CC BY-SA 4.0
2021-04-27T11:24:20.173
75539
2021-04-28T09:11:45.970
2021-04-28T04:51:03.313
3068
32521
question
javascript reactjs
react-draggableのドラッグ時動く関数内でデフォルトの引数を使いつつ、任意の渡したい変数も渡せる書き方がわからない。


react-draggableのドキュメントでは、`onDrag` に渡すべき関数は `(e: Event, data: DraggableData) =>
void | false` になっています。

<https://github.com/react-grid-layout/react-draggable#draggable-props>

>
[code]

>     //
>     // Types:
>     //
>     type DraggableEventHandler = (e: Event, data: DraggableData) => void |
> false;
>     type DraggableData = {
>       node: HTMLElement,
>       // lastX + deltaX === x
>       x: number, y: number,
>       deltaX: number, deltaY: number,
>       lastX: number, lastY: number
>     };
>  
[/code]

JSXでは `{}` で囲まれた中に任意のJavaScriptコードが記述できます。

<https://ja.reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-
jsx>

> あらゆる有効な JavaScript の式を JSX 内で中括弧に囲んで使用できます。

`playerColorList.map()` に渡しているアロー関数の引数である `color`
はクロージャで参照可能なため、以下の様な関数(アロー関数)を `onDrag` prop に指定すればいいのではないでしょうか？

(`handleDrag`の戻り値の型がvoidである前提)

[code]

    const handleDrag = (e, data, color) => {
      // do something.
    };
    
    const playersIcon = playerColorList.map((color) => (    
      <Grid item xs={1} key={color}> 
        <Draggable
          position={playerIconPosition[color]}
          onDrag={(e, data) => { handleDrag(e, data, color); }}
        >
          <img src={playerColorImageList[color]} className={classes.img}/>
        </Draggable>
      </Grid>
    ));
    
[/code]

アロー関数式 - JavaScript | MDN  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions>

クロージャ - JavaScript | MDN  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures>

* * *

または、カリー化と部分適用を使って以下の様に書くこともできます。

[code]

    const handleDrag = (color) => (e, data) => {
      // do something.
    };
    
    const playersIcon = playerColorList.map((color) => (    
      <Grid item xs={1} key={color}> 
        <Draggable
          position={playerIconPosition[color]}
          onDrag={handleDrag(color)}
        >
          <img src={playerColorImageList[color]} className={classes.img}/>
        </Draggable>
      </Grid>
    ));
    
[/code]

* * *

また、`playerColorList.map()`で返すReact Elementには上記のコードの様に `key` を指定してください。

[リストと key – React](https://ja.reactjs.org/docs/lists-and-keys.html)


CC BY-SA 4.0
2021-04-28T04:46:33.100
75549
2021-04-28T09:11:45.970
2021-04-28T09:11:45.970
3068
3068
75539
answer