React/FastAPI初心者が3日でCRUDする(1週間だけ頑張る Day6of9)

#　はじめに
1週間N(E)ETになった社会人の学習記録です。
今日もReactのサンプルを写経し、使い方を覚えます。
前回はReadまでできたので、Create/Update/Deleteを作ります。

https://qiita.com/tagawa0525/items/2973d9cf15fce154e5ad

# 実装
基本、参考サイト[^1] [^2] [^3]のコピペ
「@material-ui/grid」から「@material-ui/data-grid」に変更した。

## Create

[^1]: https://zenn.dev/tatsurom/articles/1bf9bf6f24e14532c58b
[^2]: https://zenn.dev/tatsurom/articles/0b212d24c80c334d70c9
[^3]: https://github.com/tatsuro-m/react_rails_api_frontend

https://github.com/tagawa0525/prac/commit/49b1aa20a76575ea733a468ad2b12ec59f7d8834

### 1.classの利用
TypeScriptを使ったので、classを使ってちょっと固くしてみた。
VSCodeのTypeScript変換予測は超優秀だなと思った。

```ts:User.ts
interface User {
  username: string;
  email: string;
  password: string;
  is_active: boolean;
  is_superuser: boolean;
}

class User {
  constructor() {
    this.username = "new user";
    this.email = "sample@example.com";
    this.password = "p@ssw0rd";
    this.is_active = true;
    this.is_superuser = false;
  }
}
```

Rubyの「instance_variable_set」相当の書き方がわからなかった。
（参考元みたいにJSONのまま使うべきなのだろうか）

```tsx:App.tsx
  handleInputChange(
    itemName: keyof User,
    e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
  ) {
    const newUser = Object.assign({}, this.state.userInput)
    // さすがにこれはダサすぎる
    switch (itemName) {
      case 'username':
        newUser.username = e.target.value;
        break;
      case 'email':
        newUser.email = e.target.value;
        break;
      case 'password':
        newUser.password = e.target.value;
        break;
    }

    this.setState({
      userInput: newUser
    });
  }
```

```js:App.js(参考元)
  handleInputChange(itemName, e) {
    const newUser = Object.assign({}, this.state.userInput)
    newUser[itemName] = e.target.value;

    this.setState({
      userInput: newUser
    });
  }
```

### 2.FastAPIの調整
FastAPIの戻り値にUser.idがなかったため、FastAPI側を修正した。

```python:router.py
# usersをidで検索して「UserSelect」をjsonにして返します。
@router.get("/users/find", response_model=UserSelect)
async def users_findone(id: int, database: Database = Depends(get_connection)):
    query = users.select().where(users.columns.id==id)
    return await database.fetch_one(query)

@router.post("/users/create", response_model=UserSelect)
async def users_create(user: UserCreate, database: Database = Depends(get_connection)):
    # validatorは省略
    query = users.insert()
    values = get_users_insert_dict(user)
    ret = await database.execute(query, values)
    # もう一回取り直すので、ここがダサい。
    return await users_findone(ret, database)
    # return {**user.dict()} # オリジナル
```

## Delete
https://github.com/tagawa0525/prac/commit/c092048d38dbe5d203bb3b437bf7e9f84bc330ed

### 1.FastAPIの調整
FastAPIのdeleteは送信する側のjsonのpropertyが必要なので、passwordを抜いたものを作った。（今思えばidだけでも良い。）

```python:schema.py
# update用のrequest model
class UserUpdate(BaseModel):
    id : int
    username: str
    email: str
    password: str # updateにはpasswordがある
    is_active: bool
    is_superuser: bool

# delete用のrequest model
class UserDelete(BaseModel):
    id : int
    username:     str  # 今改めて考えたら不要
    email:        str  # 今改めて考えたら不要
    is_active:    bool # 今改めて考えたら不要
    is_superuser: bool # 今改めて考えたら不要
```

### 2.RESTのPath調整
RailsはとAPIのRESTが微妙に違うので調整。

```ts
    this.axios.delete(`/users/${id}`)           // for Rails
    this.axios.post("/users/delete/", userJson) // for FastAPI
```

## Update
Modalはやめた。

https://github.com/tagawa0525/prac/commit/646b7009f9c13d3fe8bc153dda451c723fb3c4b4

 
## 所感
createやアップデートで作った分だけReact側のデータを更新するのは面白いなと思った。

```tsx:App.tsx
  handleUserSubmit(e: { preventDefault: () => void; }) {
    e.preventDefault();
    const userJson = JSON.stringify(this.state.userInput);

    this.axios.post("/users/create", userJson)
      .then((res: { [x: string]: any; }) => {
        // ここのブラウザ側の情報更新を一部だけで済ましているのは賢いなと思った。
        const users = this.state.users.slice();
        users.push(res["data"]);
        this.setState({
          users: users,
          userInput: new User(),
        });
      })
      .catch((data: any) => {
        console.log(data)
      });
  }
```

やっぱりViewは好きじゃない。
予定より2日ほど遅れたので、このまま進むか悩み中。

## 免責事項（言い訳）
上記の技術については初心者なので、あてにしないように!!!