Next.js × Supabase で作る TODO アプリ

# はじめに
この記事は [フィヨルドブートキャンプ Part 2 Advent Calendar 2024](https://adventar.org/calendars/10807) の10日目の記事です。

フィヨルドブートキャンプのアドベントカレンダー2024には、以下の2つがあります：
- [フィヨルドブートキャンプ Part 1 Advent Calendar 2024](https://adventar.org/calendars/10357)
- [フィヨルドブートキャンプ Part 2 Advent Calendar 2024](https://adventar.org/calendars/10807)

昨日(12/9)は beta_chelsea さんの[ヒトは如何にしてGitの習得に至るのかを考え中](https://beta-chelsea.hatenadiary.jp/entry/2024/12/09/234303)でした。チーム開発に参加して `git` のことを実践的に学びたいと思いました。

# 成果物

https://github.com/kazuma-naka/supabase-sample-todos


Neomorphism デザインを取り入れた TODO アプリです。

![成果物](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569408/5b28f3f1-5f58-7c5d-c821-b55ff8ffded4.gif)


# 🔖 目次
[1. 自己紹介](#1-自己紹介)  
[2. 環境の準備](#2-環境の準備)  
[3. Supabase のセットアップ](#3-supabase-のセットアップ)  
[4. アプリケーションの構築](#4-アプリケーションの構築)  
[5. 動的ルーティングでのタスク編集](#5-動的ルーティングでのタスク編集)  
[6. Neomorphism デザインの適用と解説](#6-neomorphism-デザインの適用と解説) 
[7. おわりに](#7-おわりに)  

# 1. 自己紹介

フィヨルドブートキャンプで学習している Kazuma です。  
フロントエンドについて学んでいます🖊  
この記事では `Next.js (14.2.18)`, `React (18.2.0)`, `Supabase (1.223.10)` を使った TODO アプリを作成します。

### 完成するアプリの主な機能：
- タスクの追加・削除
- タスクの完了状態の切り替え
- タスクテーブルのリセット
- タスク編集 (動的ルーティング対応)

# 2. 環境の準備

### 必要なツール
1. **Node.js** (16 以上)
2. **Next.js** (14.2.18)
3. **Supabase CLI**
   - [Supabase CLI インストールガイド](https://supabase.com/docs/guides/cli) を参考にしてください。

### プロジェクトの作成

```shell
npx create-next-app@14.2.18 todo-app
cd todo-app
npm install @supabase/supabase-js
```

Supabase をローカルで動作させるために CLI を使用してセットアップします。

```bash:
npx supabase init
npx supabase start

npx supabase status
```
Supabase の URL と `anon` キーを `.env.local` に記載する

```bash:.env.local
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon_key>
```

# 3. Supabase のセットアップ

### テーブル作成
Supabase の SQL エディタで以下のクエリを実行し、`todos` テーブルを作成します：

```sql:Supabase Studio内の SQL Editor
create table todos (
  id uuid primary key default gen_random_uuid(),
  task text not null,
  is_complete boolean default false,
  created_at timestamp default now()
);
```

# 4. アプリケーションの構築

### **`app/page.tsx` の解説**

#### **1. タスクの取得 (`fetchTodos`)**
Supabase の `todos` テーブルからデータを取得してリストに表示します。

```typescript
const fetchTodos = async () => {
  const { data, error } = await supabase
    .from('todos')
    .select('*')
    .order('created_at', { ascending: true });
  if (!error) setTodos(data || []);
};
```

#### **2. タスクの追加 (`addTodo`)**
入力されたタスクを Supabase に挿入し、リストを更新します。

```typescript
const addTodo = async () => {
  if (!newTask.trim()) return;
  const { data } = await supabase
    .from('todos')
    .insert([{ task: newTask }])
    .select('*');
  setTodos((prev) => [...prev, ...(data || [])]);
  setNewTask('');
};
```

#### **3. タスクの完了状態の切り替え (`toggleComplete`)**
タスクの完了状態を反転させます。

```typescript
const toggleComplete = async (id: string, currentState: boolean) => {
  const { error } = await supabase
    .from('todos')
    .update({ is_complete: !currentState })
    .eq('id', id);
  if (!error) {
    setTodos((prev) =>
      prev.map((todo) =>
        todo.id === id ? { ...todo, is_complete: !currentState } : todo
      )
    );
  }
};
```

# 5. 動的ルーティングでのタスク編集

### 動的ルーティングの設定
`app/pages/edit/[id].tsx` を作成して、動的ルーティングを設定します。  
この仕組みにより、URL の `id` を元に特定のタスクを編集できます。

### **`[id].tsx` の解説**

#### **1. タスクの取得**
URL パラメータから `id` を取得し、Supabase を使用して該当タスクを取得します。

```typescript
const fetchTask = useCallback(async () => {
  const { data } = await supabase
    .from('todos')
    .select('task')
    .eq('id', id)
    .single();
  setTask(data?.task || '');
}, [id]);
```

#### **2. タスクの更新**
入力した新しいタスク名で該当タスクを更新します。

```typescript
const updateTask = async () => {
  await supabase.from('todos').update({ task }).eq('id', id);
  router.push('/');
};
```

#### **3. タスクの削除**
削除ボタンをクリックすると、タスクが削除されてホームに戻ります。

```typescript
const deleteTask = async () => {
  if (confirm('Are you sure you want to delete this task?')) {
    await supabase.from('todos').delete().eq('id', id);
    router.push('/');
  }
};
```

# 6. Neomorphism デザインの適用と解説

ここでは、アプリの UI に **Neomorphism デザイン** を取り入れる方法を詳しく解説します。

### Neomorphism デザインの要点

Neomorphism デザインの基本原則は以下の通りです：

1. **光と影**:
   - 背景色に近い要素の色を選択。
   - 明るい影と暗い影を `box-shadow` で表現。
2. **エッジの柔らかさ**:
   - `border-radius` を使用して要素に丸みを持たせます。
3. **トランジション効果**:
   - インタラクティブな操作時にアニメーションを加えます。

## プレビュー

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="KwPzJvx" data-pen-title="Untitled" data-user="Kazuma-Naka" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Kazuma-Naka/pen/KwPzJvx">
  Untitled</a> by Kazuma Naka (<a href="https://codepen.io/Kazuma-Naka">@Kazuma-Naka</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 7. おわりに

この記事では、Next.js と Supabase を使用して作成した TODO アプリを作成する方法を解説しました。Next.js を使うと、動的ルーティングを簡単に設定でき、編集ページを実装したい際に活用できます。