Blitz.jsとRedisを使用してToDoリストを作成する
Blitz.jsは、もともとNext.jsからフォークされたReactフレームワークです。今日は、Upstashにタスクを保存するBlitz.jsTo-Doアプリケーションを作成します。面倒なことはせずに、始めましょう!
開始するには、コンピューターにBlitz.jsをインストールする必要があります。
NPM:
npm install -g blitz --legacy-peer-deps
糸:
yarn global add blitz
新しいBlitz.jsアプリを作成するには、 blitz new
を使用します ディレクトリに挿入します。
blitz new blitzjs-todo && cd blitzjs-todo
では、TailwindCSSをインストールしてWebサイトのスタイルを設定しましょう。
blitz install tailwind
最後に、Upstash JS SDKをインストールして、UpstashAPIの呼び出しを簡単にしましょう。
NPM:
npm i @upstash/redis
糸:
yarn i @upstash/redis
この時点で、 blitz dev
を実行する必要があります すべてが正しく機能していることを確認します。アカウントを作成してサインインしてみてください。これまでにすべてを正しく行った場合は、次のようになります。
さらに、ファイル構造は次のようになります。
これらのUPSTASH_REDIS_REST_URL
をコピーします およびUPSTASH_REDIS_REST_TOKEN
Upstashコンソールから.env
というファイルに 今のところ。次のようになります:
# This env file should be checked into source control
# This is the place for default values for all environments
# Values in `.env.local` and `.env.production` will override these values
UPSTASH_REDIS_REST_URL=YOUR_URL_HERE
UPSTASH_REDIS_REST_TOKEN=YOUR_TOKEN_HERE
これで、Blitz.jsアプリケーションが完全にセットアップされました。 To-Doリストの実装を始めましょう。
Blitz.jsにはユーザー認証が組み込まれています!これを活用して、ユーザーごとにプライベートなToDoリストを作成しましょう。
まず、 /lib/redis.ts
でUpstashJSSDKを初期化します。
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
export default redis;
3を作成する必要があります To-DoリストにアクセスするためのさまざまなAPIルート。
app / api
に移動します getall.ts
というファイルを作成します 。完了したら、次のコードを貼り付けます。
import { BlitzApiRequest, BlitzApiResponse, getSession } from "blitz";
import redis from "../../lib/redis";
export const handler = async (req: BlitzApiRequest, res: BlitzApiResponse) => {
const session = await getSession(req, res);
if (!session.userId) {
res.status(401).json({ error: `Do not tamper with this route!` });
} else {
await redis
.lrange(String(session.userId), 0, 100)
.then((data) => res.status(200).json({ data: data, success: true }))
.catch((error) => res.status(500).json({ error: error }));
}
};
export default handler;
このAPIルートがどのように機能するかを段階的に見ていきましょう。まず、ルートをリクエストします。ルート自体で、ユーザーがログインしていることを検証します。ユーザーがいない場合は、「NotAuthorized」応答を返します。 ある場合 ユーザーの場合、Upstash Redisデータベースをフェッチして、現在リストにあるすべてのTo-Doを検索します。これにより、約100のTo-Doが取得されます。
Q:待ってください、そもそもTo-Doをどのように追加するのですか?A:良い質問です!次にやってみましょう!
もう一度、次のコードを add.ts
という新しいファイルに貼り付けます app / api
で 。
import { BlitzApiRequest, BlitzApiResponse, getSession } from "blitz";
import redis from "../../lib/redis";
const handler = async (req: BlitzApiRequest, res: BlitzApiResponse) => {
const session = await getSession(req, res);
if (req.method !== "POST" || !req.body.data || !session.userId) {
res.status(401).json({ error: `Do not tamper with this route!` });
} else {
let todo = encodeURI(req.body.data);
await redis
.lpush(String(session.userId), todo)
.then(() => res.status(200).json({ success: true }))
.catch(() => res.status(500).json({ error: "Error adding data." }));
}
};
export default handler;
このAPIルートは前のルートと非常に似ていますが、5行目にさらにチェックが追加されていることに注意してください。これは、このリクエストが GET
ではないためです リクエストではなく、 POST
リクエスト。 3つのことをチェックする方法に注目してください。 まず、リクエストが実際に POST
であることを確認します リクエスト。次に、 req.body.data
にJSONまたはテキストがあることを確認します 。最後に、ユーザーがログインしていることを確認します。これらの小さなチェックがすべて合格すると、To-DoをUpstashのRedisリストにプッシュできます。フェッチ中に何らかのエラーが発生した場合は、 .catch
を使用して500を返すことができます。 。
追加する必要がある最後のルートは、To-Doを削除するルートです。何かを終えたら、もちろんそれを消さなければなりません!最後のAPIルートをapp/ api / remove.ts
に追加しましょう 。次のコードをファイルにコピーします:
import { BlitzApiRequest, BlitzApiResponse, getSession } from "blitz";
import redis from "../../lib/redis";
const handler = async (req: BlitzApiRequest, res: BlitzApiResponse) => {
const session = await getSession(req, res);
if (req.method !== "POST" || !req.body.data || !session.userId) {
res.status(401).json({ error: `Do not tamper with this route!` });
} else {
let todo = encodeURI(req.body.data);
await redis
.lrem(String(session.userId), 1, todo)
.then(() => res.status(200).json({ success: true }))
.catch(() => res.status(500).json({ error: "Error removing data." }));
}
};
export default handler;
似たようなものに気づきましたか?これは、このルートが add
とほぼ同じであるためです。 APIルート。ここでの主な違いは、 LREM
を使用していることです。 、 LPUSH
ではありません 、Redisからアイテムを削除します。
まず、 app / pages / index.js
内のすべてを削除しましょう To-Doリストを段階的に作成します。
ファイルの先頭に、これらのインポートを貼り付けます。
import { Link, BlitzPage, useMutation, Routes, getAntiCSRFToken } from "blitz";
import { useRef, useEffect, useState, Suspense } from "react";
import Layout from "app/core/layouts/Layout";
import { useCurrentUser } from "app/core/hooks/useCurrentUser";
import logout from "app/auth/mutations/logout";
React Hooksを使用して、To-Doリストのコア機能を構築します。リストのコア機能のいくつかを実装しましょう。
const Main = () => {
const todoRef = useRef<HTMLInputElement>(null)
const [todos, setTodos] = useState([])
const currentUser = useCurrentUser()
const [logoutMutation] = useMutation(logout)
const handleAddTodo = async (e) => {
e.preventDefault()
const antiCSRFToken = await getAntiCSRFToken()
const response = await fetch("/api/add", {
method: "POST",
headers: {
"Content-Type": "application/json",
"anti-csrf": antiCSRFToken,
},
body: JSON.stringify({ data: todoRef.current?.value }),
})
const data = await response.json()
if (data.success) {
todoRef.current!.value = ""
fetchTodos()
}
}
const handleRemoveTodo = async (id) => {
const antiCSRFToken = await getAntiCSRFToken()
const response = await fetch("/api/remove", {
method: "POST",
headers: {
"Content-Type": "application/json",
"anti-csrf": antiCSRFToken,
},
body: JSON.stringify({ data: id }),
})
const data = await response.json()
if (data.success) {
fetchTodos()
}
}
const fetchTodos = async () => {
const antiCSRFToken = await getAntiCSRFToken()
const response = await fetch("/api/getall", {
method: "GET",
headers: {
"anti-csrf": antiCSRFToken,
},
})
const res = await response.json()
setTodos(res.data)
}
useEffect(() => {
fetchTodos()
}, [])
if (currentUser) {
return (
<>
<button
className="mt-4 px-2 py-1 border-2 border-black hover:bg-gray-400 mb-3"
onClick={async () => {
await logoutMutation()
}}
>
Logout
</button>
<div>
User id: <code>{currentUser.id}</code>
<br />
User email: <code>{currentUser.email}</code>
</div>
<form className="mt-2" onSubmit={handleAddTodo}>
<p>add a todo:</p>
<input
ref={todoRef}
className="w-full border-black border-2 focus:outline-none text-center"
/>
</form>
<div className="flex flex-col gap-2 mt-4 bg-gray-300 rounded-md">
{(todos as string[]).map((todo: string, index: number) => (
<div className="flex items-center p-3 rounded-md bg-gray-300" key={index}>
<button
onClick={() => handleRemoveTodo(todo)}
className="flex items-center mr-4 justify-center w-5 h-5 rounded-[0.25rem] border border-solid border-gray-500 shadow-sm hover:bg-gray-700"
></button>
<span>{todo}</span>
</div>
))}
</div>
</>
)
} else {
return (
<div className="flex flex-col gap-4 text-center">
<Link href={Routes.SignupPage()}>
<a className="mt-4 px-2 py-1 border-2 border-black hover:bg-gray-400">
<strong>Sign Up</strong>
</a>
</Link>
<Link href={Routes.LoginPage()}>
<a className="mt-4 px-2 py-1 border-2 border-black hover:bg-gray-400">
<strong>Login</strong>
</a>
</Link>
</div>
)
}
}
<メイン/>コード> コンポーネントは、アプリケーションの中核です。そのコードを詳しく見ると、その使用方法がわかります。コンポーネントの上部で、アプリケーションの状態を初期化します。
ref
も宣言します 後で「新しいTo-Do」入力で使用するため。 antiCSRFToken
の使用法にも気付くかもしれません ! Blitz.jsでは、あらゆる種類の悪意のあるアクターがサイトに害を及ぼすのを防ぐために、APIルートをフェッチするときにこれらのトークンを使用する必要があります。私の意見では、持っているのはいいことです!
ウェブサイト上のデータを処理するために、3つの主要な機能を使用しています。これらの3つは次のとおりです。
-
handleAddTodo
-
handleRemoveTodo
-
fetchTodos
fetchTodos
と呼びます ページが読み込まれるとすぐに、ユーザーが完了する必要のあるすべてのTo-Doを読み込みます。ユーザーがTo-Doを削除または追加すると、 fetchTodos
が呼び出されます。 その変更をウェブサイトに反映するためにもう一度!
ユーザーがログインしていない場合、ユーザーはこのページを表示する前にWebサイトにログインするように求められます。
Webサイトでまだセッションを行っていない場合は、サインアップまたはログインできます。アカウントなしでTo-Doを保存することはできません。また、すべてのAPIルートでは、 AntiCSRFToken
で認証される必要があります。 !
しかし、待ってください、もう1つの重要なステップです!ページをエクスポートする必要があります!
const Home: BlitzPage = () => {
return (
<div className="flex flex-col min-h-screen items-center justify-center">
<main>
<div className="my-4">
<Suspense fallback="Loading...">
<Main />
</Suspense>
</div>
</main>
</div>
);
};
Home.suppressFirstRenderFlicker = true;
Home.getLayout = (page) => <Layout title="Home">{page}</Layout>;
export default Home;
上記のように、Blitz.jsはNextとは少し異なるアプローチを使用していますが、アプローチは今のところコアで同じです。 Suspense
を使用します 以前にインポートして、アプリが読み込まれていることをユーザーに表示してから、
を表示します。 読み込みが完了した後のコンポーネント!
変更が有効になっていることを確認するには、コンソールでこれをもう一度実行し、ブラウザでアプリに移動します。
blitz dev
指示に従った場合、ログインしていくつかのTo Doを追加すると、アプリケーションはこれに沿って何かを確認する必要があります。
To-Doの横にあるボックスをクリックすると、To-Doを削除できます。これが、 removeTodo
です。 関数は😉用です。
おめでとうございます!
このブログ投稿を読んで何か新しいことを学んだことを願っています。学んでいない場合でも、スキルを磨いても問題はないことを忘れないでください。 Blitz.jsはNext.jsから焦点を移しているため、将来的には完全に異なるフレームワークになる可能性がありますが、こちらのWebサイトに注目してください!
プロジェクトソース :GitHubリンク
作業デモ: デモリンク
フィードバックがありますか? Twitterで@upstashをフォローし、Discordサーバーに参加してください!
-
エッジキャッシングを使用した5ミリ秒のグローバルRedisレイテンシ
データベースとクライアントが同じリージョンにある場合、Redisを使用すると1ミリ秒のレイテンシーが簡単になります。ただし、クライアントをグローバルに分散させたい場合は、遅延が100ミリ秒を超えて増加します。これを克服するためにEdgeCachingを構築しました。 エッジキャッシング エッジキャッシングを使用すると、REST応答は、CDNと同様に、世界中のエッジロケーションにキャッシュされます。エッジキャッシングが有効になっている場合、平均で5msのグローバルレイテンシが見られます。 10の異なるリージョンにあるクライアントからのレイテンシー数を記録するベンチマークアプリケーションを参照し
-
CloudflareワーカーとのRedis@Edge
エッジでのコンピューティングは、近年最もエキサイティングな機能の1つです。 CDNを使用すると、ファイルをユーザーに近づけることができます。エッジコンピューティングを使用すると、アプリケーションをユーザーの近くで実行できます。これは、開発者がグローバルに分散されたパフォーマンスの高いアプリケーションを構築するのに役立ちます。 Cloudflare Workersは、現在この分野の主要製品です。コールドスタートのないサーバーレス処理環境を提供します。 Cloudflareのグローバルネットワークを活用して、アプリケーションのレイテンシーを最小限に抑えます。関数はJavascript、Rust、