এই পোস্টে, আমরা Remix এবং Serverless Redis (Upstash) ব্যবহার করে একটি সাধারণ TODO অ্যাপ লিখব।
রিমিক্স হল একটি সম্পূর্ণ স্ট্যাক ওয়েব ফ্রেমওয়ার্ক যা আপনাকে ব্যবহারকারীর ইন্টারফেসের উপর ফোকাস করতে এবং দ্রুত, চটকদার এবং স্থিতিস্থাপক ব্যবহারকারীর অভিজ্ঞতা প্রদানের জন্য ওয়েব মৌলিক বিষয়গুলির মাধ্যমে আবার কাজ করতে দেয়৷
রিমিক্স প্রকল্প তৈরি করুন
নিচের কমান্ডটি চালান:
npx create-remix@latest
প্রকল্প প্রস্তুত. এখন নির্ভরতা ইনস্টল করুন এবং রান করুন:
npm install
npm run dev
ইউজার ইন্টারফেস
আমরা একটি সাধারণ ফর্ম এবং করণীয় আইটেমগুলির জন্য একটি তালিকা তৈরি করব:
// app/routes/index.tsx
import type { ActionFunction, LoaderFunction } from "remix";
import { Form, useLoaderData, useTransition, redirect } from "remix";
import { useEffect, useRef } from "react";
import type { Todo } from "~/components/todo-item";
import TodoItem from "~/components/todo-item";
export const loader: LoaderFunction = async () => {
// example data
return [
{ id: 1, text: "Task 1", status: false },
{ id: 2, text: "Task 2", status: true },
];
};
export const action: ActionFunction = async ({ request }) => {
// this will be used for create, update and delete operations
};
export default function Index() {
// for loading and form actions
const transition = useTransition();
// to use the loaded data in the page
const todos: Todo[] = useLoaderData();
const isCreating = transition.submission?.method === "POST";
const isAdding = transition.state === "submitting" && isCreating;
// split the finished and unfinished items
const uncheckedTodos = todos.filter((todo) => !todo.status);
const checkedTodos = todos.filter((todo) => todo.status);
const formRef = useRef<HTMLFormElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
// reset the form after the create
if (isAdding) return;
formRef.current?.reset();
inputRef.current?.focus();
}, [isAdding]);
return (
<main className="container">
{/* crete form */}
<Form ref={formRef} method="post">
<input
ref={inputRef}
type="text"
name="text"
autoComplete="off"
className="input"
placeholder="What needs to be done?"
disabled={isCreating}
/>
</Form>
{/* uncompleted tasks */}
<div className="todos">
{uncheckedTodos.map((todo) => (
<TodoItem key={todo.id} {...todo} />
))}
</div>
{/* completed tasks */}
{checkedTodos.length > 0 && (
<div className="todos todos-done">
{checkedTodos.map((todo) => (
<TodoItem key={todo.id} {...todo} />
))}
</div>
)}
</main>
);
}
এখানে আমাদের TODO উপাদান:
// app/components/todo-item.tsx
import { Form } from "remix";
export type Todo = { id: string; text: string; status: boolean };
export default function TodoItem({ id, text, status }: Todo) {
return (
<div className="todo">
<Form method="put">
{/* this hidden input will keep the data for our todo item */}
<input
type="hidden"
name="todo"
defaultValue={JSON.stringify({ id, text, status })}
/>
{/* Remix forms are just like traditional web forms. I like this. */}
<button type="submit" className="checkbox">
{status && "✓"}
</button>
</Form>
<span className="text">{text}</span>
</div>
);
}
এখন আমাদের CSS ফাইল যোগ করার সময়। একটি CSS ফাইল তৈরি করুন app/styles/app.css
:
:root {
--rounded: 0.25rem;
--rounded-md: 0.375rem;
--gray-50: rgb(249, 250, 251);
--gray-100: rgb(243, 244, 246);
--gray-200: rgb(229, 231, 235);
--gray-300: rgb(209, 213, 219);
--gray-400: rgb(156, 163, 175);
--gray-500: rgb(107, 114, 128);
--gray-600: rgb(75, 85, 99);
--gray-700: rgb(55, 65, 81);
--gray-800: rgb(31, 41, 55);
--gray-900: rgb(17, 24, 39);
}
*,
::before,
::after {
box-sizing: border-box;
border: 0;
padding: 0;
}
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
font-size: 100%;
line-height: inherit;
color: inherit;
margin: 0;
padding: 0;
}
button {
cursor: pointer;
background-color: white;
}
html {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe
UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif,
Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: var(--gray-800);
}
.container {
padding: 8rem 1rem 0;
margin: 0 auto;
max-width: 28rem;
}
.input {
width: 100%;
padding: 0.75rem 1rem;
background-color: var(--gray-100);
border-radius: var(--rounded-md);
}
.input::placeholder {
color: var(--gray-400);
}
.input:disabled {
color: var(--gray-600);
background-color: var(--gray-200);
}
.todos {
margin-top: 1.5rem;
}
.todos.todos-done {
background-color: var(--gray-100);
color: var(--gray-500);
border-radius: var(--rounded-md);
}
.todo {
display: flex;
align-items: center;
padding: 0.75rem;
border-radius: var(--rounded-md);
}
.todo + .todo {
border-top: 1px solid var(--gray-100);
}
.todo .checkbox {
display: flex;
align-items: center;
justify-content: center;
width: 1.25rem;
height: 1.25rem;
border-radius: var(--rounded);
border: 1px solid var(--gray-300);
box-shadow: 0 1px 1px 0 rgb(0 0 0 / 10%);
}
.todo .text {
margin-left: 0.75rem;
}
root.tsx
এর অধীনে css আমদানি করুন :
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "remix";
import type { MetaFunction } from "remix";
import styles from "./styles/app.css";
export function links() {
return [{ rel: "stylesheet", href: styles }];
}
export const meta: MetaFunction = () => {
return { title: "Remix Todo App with Redis" };
};
export default function App() {
// ...
}
এখন আপনার দেখতে হবে:
ডাটাবেস প্রস্তুত করুন
আমরা আমাদের ডেটা Upstash Redis-এ রাখব। তাই একটি Upstash ডাটাবেস তৈরি করুন। আমরা HTTP ভিত্তিক Upstash ক্লায়েন্ট ব্যবহার করব। আসুন ইনস্টল করি:
npm install @upstash/redis
:::noteUpstash Redis API-এর সাথে সামঞ্জস্যপূর্ণ, তাই আপনি যেকোনো Redis ক্লায়েন্ট ব্যবহার করতে পারেন কিন্তু আপনাকে নিচের কোড পরিবর্তন করতে হবে।:::
আমরা শুধুমাত্র ফর্ম জমা দিয়ে নতুন TODO আইটেম যোগ করতে পারেন. আমরা নতুন আইটেম রেডিস হ্যাশে সংরক্ষণ করি।
UPSTASH_REDIS_REST_URL
কপি/পেস্ট করুনUPSTASH_REDIS_REST_TOKEN
Upstash কনসোল থেকে।
// app/routes/index.tsx
// ...
import { Redis } from "@upstash/redis";
const redis = new Redis({
url: "UPSTASH_REDIS_REST_URL",
token: "UPSTASH_REDIS_REST_TOKEN",
});
export const action: ActionFunction = async ({ request }) => {
const form = await request.formData();
if (request.method === "POST") {
const text = form.get("text");
if (!text) return redirect("/");
await redis.hset("remix-todo-example", {
[Date.now().toString()]: {
text,
status: false,
},
});
}
// to fetch the list after each operation
return redirect("/");
};
// ...
এখন আইটেম তালিকা করা যাক:
// app/routes/index.tsx
export const loader: LoaderFunction = async () => {
const res = await redis.hgetall<Record<string, object>>(DATABASE_KEY);
const todos = Object.entries(res ?? {}).map(([key, value]) => ({
id: key,
...value,
}));
// sort by date (id=timestamp)
return todos.sort((a, b) => parseInt(b.id) - parseInt(a.id));
};
আমরা 'তৈরি' এবং 'তালিকা' কার্যকারিতা আছে. এখন আমরা সেই অংশটি বাস্তবায়ন করব যেখানে ব্যবহারকারী একটি করণীয় আইটেমকে সম্পন্ন হিসাবে চিহ্নিত করতে পারে।
// app/routes/index.tsx
export const action: ActionFunction = async ({ request }) => {
const form = await request.formData();
// create
if (request.method === "POST") {
// ...
}
// update
if (request.method === "PUT") {
const todo = form.get("todo");
const { id, text, status } = JSON.parse(todo as string);
await redis.hset("remix-todo-example", {
[id]: {
text,
status: !status,
},
});
}
return redirect("/");
};
এখন সবকিছু প্রস্তুত! আমি Next.js এবং SvelteKit এর সাথে একই TODO অ্যাপ্লিকেশন বাস্তবায়ন করার পরিকল্পনা করছি। তারপর আমি এই ফ্রেমওয়ার্কগুলিতে আমার অভিজ্ঞতা তুলনা করব।
সাথে থাকুন এবং Twitter এবং Discord-এ আমাদের অনুসরণ করুন৷
৷প্রজেক্ট সোর্স কোড
https://github.com/upstash/redis-examples/tree/master/remix-todo-app-with-redis
প্রকল্প ডেমো পৃষ্ঠা
https://remix-todo-app-with-redis.vercel.app/