🌐

Next14でSupbaseを使ってみる

2024/10/20に公開

公式チュートリアルをやってデータの表示をやってみよう

Next14を使用して、Supabase公式を見ながら作成したnotesテーブルからデータの取得をやってみた。
https://supabase.com/docs/guides/getting-started/quickstarts/nextjs

Supabase プロジェクトの作成
database.newにアクセスし、新しい Supabase プロジェクトを作成します。
プロジェクトが起動したら、テーブルエディタで新しいテーブルを作成し、データを挿入します。
また、プロジェクトのSQLエディタで以下のスニペットを実行することもできます。これで、いくつかのサンプルデータを含むノートテーブルが作成されます。

-- Create the table
create table notes (
  id bigint primary key generated always as identity,
  title text not null
);

-- Insert some sample data into the table
insert into notes (title)
values
  ('Today I created a Supabase project.'),
  ('I added some data and queried it from Next.js.'),
  ('It was awesome!');

alter table notes enable row level security;

RLS ポリシーを追加することで、テーブルのデータを一般に読めるようにします:

create policy "public can read notes"
on public.notes
for select to anon
using (true);

Next.jsアプリの作成
create-next-appコマンドとwith-supabaseテンプレートを使って、次のように設定されたNext.jsアプリを作成します:

Cookieベースの認証
タイプスクリプト
Tailwind CSS

npx create-next-app -e with-supabase

Supabase環境変数の宣言
.env.exampleを .env.localにリネームし、Supabaseの接続変数を入力します:

NEXT_PUBLIC_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>

こんな感じでやります。

Next.jsからSupabaseのデータをクエリする
app/notes/page.tsxに新しいファイルを作成し、次のように入力します。
これにより、Supabaseのノートテーブルからすべての行が選択され、ページにレンダリングされます。

app/notes/page.tsx
  import { createClient } from '@/utils/supabase/server';

  export default async function Notes() {
    const supabase = createClient();
    const { data: notes } = await supabase.from("notes").select();

    return <pre>{JSON.stringify(notes, null, 2)}</pre>
  }

server.tsも必要なので作成する。

utils/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export function createClient() {
  const cookieStore = cookies()

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll()
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            )
          } catch(e) {
            // The `setAll` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
            console.error(`supabase connet error: ${e}`)
          }
        },
      },
    }
  )
}

notes/のURLにアクセスするとJSONのデータが表示されると思います。
http://localhost:3000/notes

このままだと分かりにくいのでUIに表示できるようにJSONのデータを変換して表示しましょう。lists/page.tsxを作成しましょう。

コードの説明をすると、コメントの通りnotesテーブルのスキーマのデータ型の定義に合わせてtypeでデータ型を定義しています。
Next14はServer Component(RSC)を使うことができて非同期関数のasyncを書くことができ「コンポーネント上から直接外部Web APIのデータを取得してレンダリングする」といったことが可能。

import { createClient } from "@/utils/supabase/server";

/**
 * @type Note
 * notesテーブルのスキーマのデータ型に合わせて定義
 * @id number
 * @title string
 */
type Note = {
    id: number;
    title: string;
};

/**
 * @Server Component(RSC)
 * Next14はServer Component(RSC)を使うことができて非同期関数のasyncを書くことができ
 * 「コンポーネント上から直接外部Web APIのデータを取得してレンダリングする」
 *  といったことが可能
 */
export default async function Lists() {
    const supabase = createClient();
    const { data: notes, error } = await supabase.from("notes").select("id, title");

    if (error) {
        console.error("Supabaseクエリエラー:", error);
        return <div>データの取得中にエラーが発生しました。</div>;
    }

    return (
        <div>
            <h1>ノート一覧</h1>
            <ul>
                {/* mapで新しい配列を生成する。 */}
                {notes?.map((note: Note) => (
                    <li key={note.id}>{note.title}</li>
                ))}
            </ul>
        </div>
    );
}

http://localhost:3000/lists

まとめ

Firebaseと比較すると使いやすそうだと思った。連携するための設定も予め公式が用意してくれているので親切なところがある。最近は日本国内のWeb開発でも使われてきているので自分も取り入れてみたいと思っていたりする。

Discussion