NEXT.jsとReact Hooksを使ってTodoアプリを10分で作る

Reactのフレームワークであり、かつ爆速でReact環境を構築できるNEXT.jsを使って、定番のTodoアプリを作ってみます。

そこにReact Hooksを使えばTodoアプリくらいなら10分もあれば作れるので、NEXT.jsまたはReact Hooksを使った事のない方は、気軽に取り組んでみてください。

# 作るもの
こんな感じの簡単なTodoアプリを作ります。
![next-react-app.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227196/8861944d-8999-b2ce-9d82-b1ffe088bc38.gif)

# 環境設定
NEXT.jsが動く環境を作ります。

まずはプロジェクトの作成。

```sh
$ mkdir next-todo-app
$ cd next-todo-app
$ npm init -y
```

次にNEXT.jsおよびReactを入れる。

```sh
$npm install --save react react-dom next
```

そこに `pages/index.jsx` を作成して、以下のReactコンポーネントのコードを書きます。

```pages/index.jsx
const App = () => {
  return <h1>Hello World!</h1>;
};

export default App;
```

`package.json` のscriptsも書き換えます。

```package.json
"scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
}
```

あとは、nextを起動させて、http://localhost:3000 でHello Worldが表示されているのを確認できれば完了です。

```sh
$ npm run dev
```

# Todoアプリを作る
NEXT.jsで一瞬でReact環境を作ることができたので、次にTodoアプリを実装していきます。

Todoアプリの基本的なコードは以下の通り

```tsx:pages/index.tsx
import { useState } from "react";

const App = () => {
  // 作成したtodoを入れておくためのstate
  const [todos, setTodos] = useState([]);
  // フォームに入力された値をtodoに登録するまでに入れておくためのstate
  const [tmpTodo, setTmpTodo] = useState("");

  const addTodo = () => {
    setTodos([...todos, tmpTodo]);
    setTmpTodo("");
  };

  return (
    <>
      <h1>Todo App</h1>
      <div className="form">
        <input
          type="text"
          name="todo"
          // formの入力値をtmpTodoで持っておく
          onChange={e => setTmpTodo(e.target.value)}
          value={tmpTodo}
        />
        <button onClick={addTodo}>Add</button>
      </div>
      <ul>
        {todos.map((todo, index) => {
          return <li key={index}>{todo}</li>;
        })}
      </ul>
      <style>{`
        h1 {
          text-align: center;
        }
        .form {
          display: flex;
          justify-content: center;
        }
        ul {
          width: 200px;
          margin: 10px auto;
        }
      `}</style>
    </>
  );
};

export default App;
```

これで、Todoアプリに登録する処理が書けました。
React Hooksの1つである`useState`を使うことで、stateの管理が一気に楽になります。

あとは、空白の状態でTodoが登録されないようにしつつ、削除処理のコードを加えて、Todoアプリは完成です。

```tsx:pages/index.tsx
import { useState } from "react";

const App = () => {
  const [todos, setTodos] = useState([]);
  const [tmpTodo, setTmpTodo] = useState("");

  const addTodo = () => {
    // formの内容が空白の場合はalertを出す
    if (tmpTodo === "") {
      alert("文字を入力してください");
      return;
    }
    setTodos([...todos, tmpTodo]);
    setTmpTodo("");
  };

  // todoを削除する処理
  const deleteTodo = index => {
    const newTodos = todos.filter((todo, todoIndex) => {
      return index !== todoIndex;
    });
    setTodos(newTodos);
  };

  return (
    <>
      <h1>Todo App</h1>
      <div className="form">
        <input
          type="text"
          name="todo"
          onChange={e => setTmpTodo(e.target.value)}
          value={tmpTodo}
        />
        <button onClick={addTodo}>Add</button>
      </div>
      <ul>
        {todos.map((todo, index) => {
          return (
            <li key={index}>
              {todo}
              {/* 削除ボタンを追加 */}
              <button onClick={() => deleteTodo(index)}>x</button>
            </li>
          );
        })}
      </ul>
      <style>{`
        h1 {
          text-align: center;
        }
        .form {
          display: flex;
          justify-content: center;
        }
        ul {
          width: 200px;
          margin: 10px auto;
        }
      `}</style>
    </>
  );
};

export default App;
```

NEXT.jsを使ってReact環境の構築が簡単になったこと、React Hooksを使ってStateの管理が簡単になったことで、Todoアプリくらいなら10分くらいで作ることができるようになりました。

他にもNEXT.jsを使うことで、

- デフォルトでサーバーサイドレンダリングされる
- デフォルトでコードスプリッティングされる
- デフォルトでSPAになっている
- ページごとのシンプルなページルーティング

などの利点があります。

まあ、複雑なことをやろうとすると厳しいところもあるNEXT.jsですが、Reactの環境構築としては秀逸なので触ってみる価値はあると思います。

今回作ったコードはこちらから
https://github.com/hiraike32/next-todo-app