Web3.0検証(14)-MeteorでTODO管理アプリの開発(新しいタスクの追加機能)

##### [前回] [Web3.0検証(13)-MeteorでTODO管理アプリの開発(MongoDBにデータ保存)](https://qiita.com/mingchun_zhao/items/9ff061d25b13557d2015)

## はじめに

前回に続き、TODO管理アプリを機能拡張します。
画面から新しいタスクを登録できるようにします。

## 端末1から、Meteorアプリを実行
```
$ cd simple-todos-react
$ meteor run
[[[[[ ~/simple-todos-react ]]]]]

=> Started proxy.
=> Started HMR server.
=> Started MongoDB.
=> Started your app.

=> App running at: http://localhost:3000/
```

## 端末2から、タスク追加用Formを作成

Formを使用し、Webサイトにデータ挿入/編集できるようにします。
ロジックをカプセル化するため、単純なFormコンポーネントを作成します。

uiフォルダに新しいファイルTaskForm.jsxを作成
```imports/ui/TaskForm.jsx
import React, { useState } from 'react';

export const TaskForm = () => {
  const [text, setText] = useState("");

  return (
    <form className="task-form">
      <input
        type="text"
        placeholder="Type to add new tasks"
      />

      <button type="submit">Add Task</button>
    </form>
  );
};
```

- Reactフック`useState`とは
    - 再レンダリングされても、関数コンポーネントのstate(変数の値)を保持可能にするフック
    - Reactによってコンポーネントが再レンダリングされると、コンポーネント内の変数は、初期値に戻される
    - 従来は、変数を保持するため、クラスコンポーネントでstateプロパティを定義する必要があった
    - `useState`フックの登場により、関数コンポーネントでも、 変数の状態を保持可能になった
        - クラスコンポーネントに比べ、より短く、簡単にコードを書ける
    - 左辺の`[text、setText]`配列について
        - textは、保存対象の値(ここでは文字列)
        - setTextは、text値の更新に使用される関数

## Appコンポーネントを更新

AppコンポーネントにTaskFormをimport
```imports/ui/App.jsx
import React from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { Task } from './Task';
import { TasksCollection } from '/imports/api/TasksCollection';
import { TaskForm } from './TaskForm';

export const App = () => {
  const tasks = useTracker(() => TasksCollection.find({}).fetch());

  return (
    <div>
      <h1>Welcome to Meteor!</h1>

      <TaskForm/>

      <ul>
        { tasks.map(task => <Task key={ task._id } task={ task }/>) }
      </ul>
    </div>
  );
};
```

## スタイルシートを更新

Formがマークから外れて見えないように、上部にマージンを設定。
CSSクラス`.task-form`を追加(FormコンポーネントのclassName属性と同名)

```client/main.css
body {
  padding: 10px;
  font-family: sans-serif;
}

.task-form {
  margin-top: 1rem;
}
```

## ブラウザでアプリを確認

ブラウザから、`http://localhost:3000/`にアクセス。
新しいタスクを追加するための、フォームが追加されています。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/45b0a3e2-5527-5731-5e55-a20f024f4e65.png)|
|:--|

## Submitハンドラを追加

`onSubmit`イベントを使用し、Submitハンドラをフォームにアタッチ。
Reactフックを`input`要素の`onChange`イベントにプラグインすることも可能。

```imports/ui/TaskForm.jsx
import React, { useState } from 'react';
import { TasksCollection } from '/imports/api/TasksCollection';

export const TaskForm = () => {
  const [text, setText] = useState("");

  const handleSubmit = e => {
    e.preventDefault();

    if (!text) return;

    TasksCollection.insert({
      text: text.trim(),
      createdAt: new Date()
    });

    setText("");
  };
 
  return (
    <form className="task-form" onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Type to add new tasks"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />

      <button type="submit">Add Task</button>
    </form>
  );
};
```

- Reactフック`useState`を使用し、`<input>`要素の値を格納
- `value`属性を`text`定数に設定することで、`input`要素がフックと同期される
- タスクの作成日がわかるように、タスクドキュメントの`createdAt`フィールドに日付を挿入

## 最新のタスクを最初に表示

最新のタスクを先頭に表示するように修正します。
Mongoクエリを`sort`することで簡単に実現できる。

```imports/ui/App.jsx
import React from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { Task } from './Task';
import { TasksCollection } from '/imports/api/TasksCollection';
import { TaskForm } from './TaskForm';

export const App = () => {
          const tasks = useTracker(() => TasksCollection.find({}, { sort: { createdAt: -1 } }).fetch());

          return (
                      <div>
                        <h1>Welcome to Meteor!</h1>

                        <TaskForm/>

                        <ul>
                          { tasks.map(task => <Task key={ task._id } task={ task }/>) }
                        </ul>
                      </div>
                    );
};
```

## 再度、ブラウザからアプリを確認

試しに、新しいタスクを登録します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/11bf8762-fdcf-bd61-c077-863a2fe951db.png)|
|:--|

すると、新しいタスクが期待とおり、一番先頭に表示されました。

## おわりに

Formから新しいタスクを登録できるようになりました。
次回は、タスクの状態更新と削除機能を追加します。
お楽しみに。

##### [次回] [Web3.0検証(15)-MeteorでTODO管理アプリの開発(タスクの更新/削除)](https://qiita.com/mingchun_zhao/items/fc699120220ea5c0d323)