QwikでTODOアプリを作ってみる（2）

https://qiita.com/ta1m1kam/items/7ec246867a16933d12e2

の続きです。

## イベントハンドリング

```js
function handleSubmit(e) {
  e.preventDefault();
  alert('Hello, world!');
}

<form onSubmit={handleSubmit}>
```

Reactの例では、上記のようにhandleSubmit関数で`e.preventDefault`を実行し、`alert`関数を発火させていますが、qwikではこのようにEventで発火させる処理として、直接`e.preventDefault`を入れて実行することができません。

以下のように設定します。
Qwikでは非同期のために、イベントハンドラがダウンロードされていません。なので代わりに`preventdefault:{eventName}`属性が存在します。

```ts
<form 
  preventdefault:submit
  onSubmit$={() => {
    alert("Hello, world")
  }
}>
```

## 状態の更新
状態の更新には `useStore`を使用します。
`useStore` は以下のようにObjectを初期値として取ります。

```js
const state = useStore({ count: 0 });
```

入力したタスクをSubmitした際にalert関数で表示させるようにしてみます。

useStoreでstateを作成し、Formコンポーネントにpropsとして渡します。

```src/routes/index.tsx
import { component$, useStore } from '@builder.io/qwik';

export default component$(() => {
 const nameStore = useStore({
    name: "",
 });

~~~~
 <Form nameStore={nameStore} />
```

そこからonChangeでnameを更新し、onSubmitで表示させます。

```src/components/form/index.tsx
import { component$ } from "@builder.io/qwik";


type Form = {
  nameStore: any 
}

export default component$(({ nameStore }: Form) => {
  return (
    <form 
      preventdefault:submit
      onSubmit$={() => {
        alert(`追加したタスクは、${nameStore.name}です。`)
      }
    }>
      <h2 className="label-wrapper">
        <label for="new-todo-input" className="label__lg">
          What needs to be done?
        </label>
      </h2>
      <input
        type="text"
        id="new-todo-input"
        className="input input__lg"
        name="text"
        autoComplete="off"
        onChange$={(e) => {
          nameStore.name = e.target.value
        }}
      />
      <button type="submit" className="btn btn__primary btn__lg">
        Add
      </button>
    </form>
  )
})
```

以下のように表示できることが確認できると思います。
![スクリーンショット 2022-12-03 23.25.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/d7682316-e361-3042-7b47-ba1848da7259.png)


### タスク管理用のstate作成
タスク管理用のstateを作成し、それをmockしているデータと置き換えます。

```diff:src/routes/index.tsx
 export default component$(() => {
-  const DATA = [
-    { id: "todo-0", name: "Eat", completed: true },
-    { id: "todo-1", name: "Sleep", completed: false },
-    { id: "todo-2", name: "Repeat", completed: false },
-  ];
+  const taskStore = useStore({
+    name: "",
+    tasks: []
+  });
-    { id: "todo-2", name: "Repeat", completed: false },
-  ];
+  const taskStore = useStore({
+    name: "",
+    tasks: []
+  });
 
-  const taskList = DATA.map((task) => (
-    <Todo id={task.id} name={task.name} completed={task.completed} />
+  const taskList = taskStore.tasks.map((task) => (
+    <Todo id={task.id} name={task.name} completed={task.completed} key={task.id} />
   ));
 
   return (
     <div className="todoapp stack-large">
       <h1>TodoMatic</h1>
-      <Form />
+      <Form taskStore={taskStore} />
       <div className="filters btn-group 
```


```diff/src/components/index.tsx
 import { component$ } from "@builder.io/qwik";
+import { nanoid } from "nanoid";
 
 
-export default component$(() => {
+type Form = {
+  taskStore: any
+}
+
+export default component$(({ taskStore }: Form) => {
   return (
-    <form>
+    <form
+      preventdefault:submit
+      onSubmit$={() => {
+        const newTask = { id: `todo-${nanoid()}`, name: taskStore.name, completed: false };
+        taskStore.tasks = [...taskStore.tasks, newTask]
+        taskStore.name = ""
+      }
+    }>
       <h2 className="label-wrapper">
         <label for="new-todo-input" className="label__lg">
           What needs to be done?
@@ -15,6 +27,10 @@ export default component$(() => {
         className="input input__lg"
         name="text"
         autoComplete="off"
+        value={taskStore.name}
+        onChange$={(e) => {
+          taskStore.name = e.target.value
+        }}
       />
       <button type="submit" className="btn btn__primary btn__lg">
         Add
```

ここまで実装するとタスクに自由に追加するところまでできます。

![スクリーンショット 2022-12-03 23.34.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/f78d9fb3-f745-ce19-137a-4a9803bf4507.png)


## タスク数を表示
タスク数の表示が固定で `3 tasks remaining` になっているのでついでにtaskListをカウントして表示させます。

```diff:src/routes/index.tsx
+  const headingText = `${taskList.length} tasks remaining`;
+
   return (
     <div className="todoapp stack-large">
       <h1>TodoMatic</h1>
@@ -25,7 +27,7 @@ export default component$(() => {
         <FilterButton category='Completed' />
       </div>
       <h2 id="list-heading">
-        3 tasks remaining
+        {headingText}
       </h2>
       <ul
         role="list"
```

![スクリーンショット 2022-12-03 23.39.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/1f1a38ed-ee25-929f-cba7-fd291693dde6.png)

明日も引き続きやっていきます。