Reactにおけるスプレッド構文の使い所

**スプレッド構文**を使うようになってからコードの可読性が上がったように感じたので、
どのようなところで使っているのかまとめます。

## スプレッド構文とは  
[配列 や オブジェクトをその場で展開する構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax)

```example.js
// Array
const odd = [1, 3]
const even = [2, 4]
const numbers = [...odd, ...even]
console.log(numbers) // [1, 3, 2, 4]

// Object
const name = {first: "Tanaka", last: "Taro"}
const age = {age: 27}
const profile = {...name, ...age}
console.log(profile) // {first: "Tanaka", last: "Taro", age: 27}
```
配列やオブジェクトをコピーするだけでなく、**マージすることが簡単に**できます。
Arrayを見るとわかりますが並び順は変わらないので注意。
配列であれば`hoge.concat()`
オブジェクトであれば、`Object.asign()`
を使い実現していたことを短い記述で同様のことを実現できるのが利点です。

```example.js
// Array
const numbers = odd.concat(even)

// Object
const profile = Object.assign(name, age)
```

## Reactではどう使うか
簡単なuserListアプリを作成し、どう使えるか見てみます。

![スクリーンショット 2020-01-04 12.55.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394488/712891a4-8400-1330-4a9e-57bdd66a882a.png)

今回のアプリは3つのファイルで構成され、[Materialize Css](https://materializecss.com/)でスタイリングしています。

```jsx:App.js
import React from 'react';
import InputForm from './components/InputForm';
import UserList from './components/UserList';

class App extends React.Component {

  constructor() {
    super()

    this.state = {
      users: []
    }

    this.addUser = this.addUser.bind(this)
  }

  addUser(inputUser) {
    this.setState({
      // ①App.jsにおけるスプレッド構文
      users: [...this.state.users, inputUser]
    })
  }

  render() {
    return (
      <div className="App" >
        <h1>Spread</h1>
        <div className="row">
          <div className="col s6 offset-s3">
            <div className="col s6">
              <InputForm addUser={this.addUser} />
            </div>
            <div className="col s6">
              <UserList users={this.state.users} />
            </div>
          </div>
        </div>
      </div >
    );
  }
}

export default App;
```

```InputForm.jsx
import React, { useState } from 'react';

const InputForm = (props) => {

  const [form, setValues] = useState({
    firstName: '',
    lastName: ''
  });

  const changeValue = e => {
    setValues({
      // ②InputForm.jsxにおけるスプレッド構文
      ...form,
      [e.target.name]: e.target.value
    });
  };

  const addUser = () => {
    props.addUser(form)
    // formの初期化
    setValues({
      firstName: '',
      lastName: ''
    });
  }

  return (
    <div>
      <div className="input-field">
        <input
          id="first_name"
          type="text"
          className="validate"
          name="firstName"
          value={form.firstName}
          onChange={changeValue}
        />
        <label htmlFor="first_name">First Name</label>
      </div>
      <div className="input-field">
        <input
          id="last_name"
          type="text"
          className="validate"
          name="lastName"
          value={form.lastName}
          onChange={changeValue}
        />
        <label htmlFor="last_name">Last Name</label>
      </div>
      <div className="btn" onClick={addUser}>
        <span>Add</span>
      </div>
    </div>
  )
}

export default InputForm
```

```UserList.jsx
import React from 'react';

const UserList = (props) => {
  return (
    <table>
      <thead>
        <tr>
          <th>First Name</th>
          <th>Last Name</th>
        </tr>
      </thead>
      {props.users.length !== 0 &&
        <tbody>
          {props.users.map((user, index) => {
            return (
              <tr key={index}>
                <td>{user.firstName}</td>
                <td>{user.lastName}</td>
              </tr>
            )
          })}
        </tbody>
      }
    </table>

  )
}

export default UserList
```

### ①App.jsにおけるスプレッド構文
```App.jsx
  addUser(inputUser) {
    this.setState({
      users: [...this.state.users, inputUser]
    })
  }
```
子コンポーネントから送られてきたinputUserとstateで管理している既存のusersをマージするために使用しています。
実際にはDBから再取得しリストを更新するため、
今回のようにユーザーを作成⇨リストを更新する時にスプレッドを使った実装はあまりしないような気がしますが、
一時的に保存する配列...
例えば、**グループメンバーの管理画面でユーザーを複数選択して、まとめて追加する**といった実装には使えます。


### ②InputForm.jsxにおけるスプレッド構文
```InputForm.jsx
  const [form, setValues] = useState({
    firstName: '',
    lastName: ''
  });

  const changeValue = e => {
    setValues({
      ...form,
      [e.target.name]: e.target.value
    });
  };
```
HooksのuseStateを使って複数の値を管理しているため、
formの値を全て展開してマージした後にセットしています。
Hooksで複数の値を用いる時は必須の処理です。

## まとめ
今回はlastName,firstNameのみのフォームでしたが、
要素が増えれば`Object.entries`を使用してうまくまとめることもできます。
[参考：React Hooksで複数のFormを扱う](https://qiita.com/ShotaroOkada/items/0136cec7b99c8cee0527)

またスプレッド構文自体はHOCなどで頻繁に登場するので、意味を把握しておくことは重要ですね。


## 宣伝(20240725 追記)
超最近、自分の趣味のメディアを仲間と一緒に作りました！
下記からアクセスしてみてください。
https://www.wai-ware.com/