Convexの動作を理解する


# 問題
@Sicut_studyさんの[【図解解説】話題の神Reactフレームワークreact-serverで技術記事投稿サイトを開発するチュートリアル【@lazarv/react-server/Convex/TypeScript】](https://qiita.com/Sicut_study/items/1d5c4f2ddac621565ce2#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)
をやっていて、Convexがどう動いているのか分からなかったのでまとめます。

# Convexとは
リアルタイムデータベースを中心にしたバックエンドサービスを提供するプラットフォームです。

# やっていること
### ConvexのProvider設定
```src/app/ConvexClientProvider.tsx
src/app/ConvexClientProvider.tsx
"use client";
import { ConvexProvider, ConvexReactClient } from "convex/react";

const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL!);

export default function ConvexClientProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return <ConvexProvider client={convex}>{children}</ConvexProvider>;
}
```

### アプリ内で、ConvexのConvexClientProviderを使えるようにする
``` src/app/(root).layout.tsx
import "./global.css";
import Header from "../components/Header";
import { Footer } from "../components/Footer";
import ConvexClientProvider from "./ConvexClientProvider";

export default function RootLayout({
  pageName,
  children,
}: React.PropsWithChildren<{
  pageName: React.ReactNode;
}>) {
  return (
    <html lang="ja">
      <body>
        <ConvexClientProvider> // ConvexClientProviderを設定
          <div className="flex flex-col min-h-screen">
            <Header pageName={pageName} />
            <main className="flex-grow">{children}</main>
            <Footer />
          </div>
        </ConvexClientProvider>
      </body>
    </html>
  );
}
```

### ConvexのAPI作成
```convex/artiles.ts
// Convex関数を作り、Convexと記事データをやり取りするファイル
// convexのコンソールから関数を確認できる

//  v オブジェクト
// 引数やデータのバリデーションを行うためのさまざまなユーティリティ関数を提供
// クエリやミューテーションの引数が特定の型や条件を満たしているかどうかを検証
import { v } from "convex/values";

// query　Getリクエスト
// mutation　POSTリクエスト
import { mutation, query } from "./_generated/server";

// 中略
export const getPopular = query({
    // get クエリはオプションの limit 引数を受け取る
    // limit 引数が提供された場合、その値を使用して取得する記事の数を制限
    // 提供されない場合は、すべての記事を取得
    args: {
        // limit 引数がオプションであり、数値型であることを指定
        limit: v.optional(v.number()),
    },
    handler: async (ctx, args) => {
        const { limit } = args;
        const articles = await ctx.db.query("articles").collect();

        const sortedArticles = articles
            .sort((a, b) => (b.viewCount ?? 0) - (a.viewCount ?? 0))
            // limit がある場合、その値を使用して配列の最初から limit の位置までの要素を抽出
            // limit がない場合（null または undefined の場合）、デフォルトで最初から10個の要素を抽出
            .slice(0, limit ?? 10);
    return sortedArticles.map((article) => {
            return {
                id: article._id,
                title: article.title,
                description: article.description,
                author: article.author,
                createdAt: article._creationTime,
                viewCount: article.viewCount,
            };
        });
    },
});
// 中略
```

Convexのコンソールから関数を確認できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881019/c8c88c56-bd65-4bef-adae-59f72cd4f7e7.png)



### トップページからGET.popular.server.tsを呼び出す
```src/app/page.tsx
const getArticles = async () => {
    // fetch は、JavaScriptの標準APIで、ネットワークリクエストを行うために使用される
    const response = await fetch(
        // 作成したAPIを叩く
        // src/app/api/articles/GET.popular.server.tsを呼ぶ
        "http://localhost:3000/api/articles/popular?limit=10",
    );
    // レスポンスをjson形式に変換
    const data = await response.json();
    return data;
};

export default async function Home() {
//中略

// PopularArticleList にarticlesを渡して描画
 <PopularArticleList articles={articles} />
//中略
```

### サーバーサイドレンダリング (SSR)でGET.popular.server.tsを呼び出す
```src/app/api/articles/GET.popular.server.ts
import { ConvexClient } from "convex/browser";
import { api } from "../../../../convex/_generated/api";

// VITE_CONVEX_URL　サーバーやAPIのURLを指し、ConvexClientの接続先を指定
const convexUrl = import.meta.env.VITE_CONVEX_URL;
if (!convexUrl) {
        throw new Error("VITE_CONVEX_URL is not defined");
}

// ConvexClientクラスのインスタンスを作成
const client = new ConvexClient(convexUrl);

// request: Requestは、HTTPリクエストの情報を含むオブジェクト
export default async function GetBlogs(request: Request) {

// 中略

    //  JS標準のURL オブジェクトを作成
    // リクエストのURLを解析して、クエリパラメータなどにアクセスできる
    const url = new URL(request.url);

// 中略

    // new Response　新しい Response オブジェクトを作成
    const response = new Response(JSON.stringify(articles))
    // console.log("response", response);
    return response;
```

# 終わりに
Convexの動作を理解するのは難しかったですが、各コンポーネントのつながりがわかって勉強になりました。

# 参考
[【図解解説】話題の神Reactフレームワークreact-serverで技術記事投稿サイトを開発するチュートリアル【@lazarv/react-server/Convex/TypeScript】](https://qiita.com/Sicut_study/items/1d5c4f2ddac621565ce2#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)