Material-UIとreact-smooth-dndでドラッグアンドドロップのテーブルを作る

Material-UIのテーブルとreact-smooth-dndを組み合わせたものがなかなか見つからなかったので、意外と手こずったので備忘録的に書きます。

完成形のイメージは下記の通りです。

![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307699/506502b0-3384-17f4-c2ec-b6e48b362119.gif)

## ライブラリの選定


ドラッグアンドドロップのライブラリには種類がいくつかありますが、
[react-smooth-dnd](https://github.com/kutlugsahin/react-smooth-dnd)を選びました。

選定理由としては、

1.ドラッグ開始する部分を指定したかった。（他のライブラリのサンプルだと列全部をドラッグしていたので）

2.記述が少なくてわかりやすかった

の2つです。

## 手こずったところ

Material-UIのテーブル内で使うと

1.余計なdivが入る

2.スタイルが崩れる(下記の画像)

![スクリーンショット 2021-03-09 22.41.25（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307699/ae5d15fa-1b90-be33-6933-17ed16d5af58.png)


という問題がありました。

## 完成サンプル 

```UserDraggable.jsx
import React, { useState }from "react";
import {
  Grid,
  Link,
  Table,
  TableBody,
  TableCell,
  TableContainer, 
  TableHead,
  TableRow,
  makeStyles
} from "@material-ui/core";
import DragHandleIcon from "@material-ui/icons/DragHandle";
import { Container, Draggable } from "react-smooth-dnd";
import arrayMove from "array-move";

const useStyles = makeStyles((theme)=>({
  hoverCursor:{
    '&:hover':{
      cursor:"pointer"
    }
  }
}))


export const UserDraggable  = (props) => {
  const classes = useStyles();

  const headCells = [
    { id: 'id', numeric: false, disablePadding: false, label: 'No', width: '10%', sortable: false},
    { id: 'name', numeric: false, disablePadding: false, label: 'ユーザー', width: '50%', sortable: false},
    { id: 'action', numeric: false, disablePadding: false, label: '', width: '40%', sortable: false}
  ]

  const [ users, setUser ] = useState([
    {id:1, name: "ユーザー1"},
    {id:2, name: "ユーザー2"},
    {id:3, name: "ユーザー3"},
    {id:4, name: "ユーザー4"}
  ])


  const deleteUser = (deletingUser) =>{
    const newUsers = users.filter((user)=>{
      return user.id !== deletingUser.id
    })
    setUser(newUsers);
  }

  const onDrop = (dropResult) => {
    const { removedIndex, addedIndex } = dropResult;
    // arrayMoveを使うと配列の操作は楽
    const newUsers = arrayMove(users, removedIndex || 0, addedIndex || 0)
    setUser(newUsers);
  };
  return(
    <React.Fragment>
      <Grid item xs={6}>
        <TableContainer>
          <Table aria-labelledby="tableTitle" size="small" className="tablePaginate" >
            <TableHead>
              <TableRow>
                {
                  headCells.map((headCell)=>{
                    return(<TableCell
                      key={headCell.id}
                      align={headCell.numeric ? 'right' : 'left'}
                      padding={headCell.disablePadding ? 'none' : 'default'}
                      style={{width: headCell.width}}>
                      {headCell.label}
                    </TableCell>)
                  })
                }
              </TableRow>
            </TableHead>

              <Container
                dragHandleSelector=".dragHandleSelector"//ここでドラッグ要素の指定
                lockAxis="y"
                onDrop={onDrop}
                //ここのrenderを使うのがポイント
                render={(ref)=>{
                  return (
                  <TableBody ref={ref}>
                    {
                      users.map((user, index) => {
                        return (
                          <Draggable
                            key={index}
                            render={(ref)=>{
                            return(
                              <TableRow
                                ref={ref}
                              >
                                <TableCell>
                                  {user.id}
                                </TableCell>
                                <TableCell>
                                  {user.name}
                                </TableCell>
                                <TableCell>
                                  <DragHandleIcon className={ "dragHandleSelector" + " " + classes.hoverCursor }/>
                                  <br/>
                                  <Link className={classes.hoverCursor} onClick={()=>{deleteUser(user)}}>
                                    行削除
                                  </Link>
                                </TableCell>
                              </TableRow>
                            )
                          }} />
                        )
                      })
                    }
                  </TableBody>)
                }}
              />
          </Table>
        </TableContainer>
      </Grid>
    </React.Fragment>
  )
}
```
スタイルでdiplayをtableに

```style.css
.smooth-dnd-container.vertical > .smooth-dnd-draggable-wrapper {
    display: table-row !important;
}
```

## 解説

余計なdivが入らないようにするには[render](https://github.com/kutlugsahin/react-smooth-dnd#render-1)を使うと解決しました。

スタイルが崩れるのは`display:block`になっていたことが原因だったのでcssで無理矢理、変更しました。cssの方はmakeStyledsであてようとしたのですがうまくいかずになくなくこの記述に。



似たような問題にぶつかっている人の助けになれば幸いです。