متن خبر

نحوه ساخت داشبورد مدیریت با React

نحوه ساخت داشبورد مدیریت با React

شناسهٔ خبر: 446884 -




آیا به داشبوردهای تعاملی در وب سایت هایی مانند Stripe نگاه کرده اید و فکر کرده اید، "چگونه می توانم خودم چیزی شبیه به این بسازم؟"

در این پروژه Full Stack React و Next.js، یاد خواهید گرفت که چگونه یک داشبورد مدیریت خیره کننده از جلو به عقب بسازید.

داشبورد مدیریت نهایی ما به شما این امکان را می دهد که کاربران تأیید شده را در جدول کاربران نمایش و جستجو کنید و داده های مهم را با استفاده از نمودارهای میله ای و خطی تعاملی نشان دهید.

admin-dashboard-2
نسخه نهایی داشبورد مدیریت ما

علاوه بر یادگیری مفاهیم مهم Next.js، با مجموعه ای از ابزارهای قدرتمند از جمله Prisma، PostgreSQL، Tremor، NextAuth و TailwindCSS آشنا خواهید شد.

فهرست مطالب

ابزارهایی برای نصب

ایجاد پایگاه داده Postgres

طرحواره پریسما را تنظیم کنید

از Prisma Client استفاده کنید

Prisma را به NextAuth وصل کنید

نوار ناوبری برنامه را بسازید

نمایش اطلاعات حساب

محافظت از مسیرها

صفحه تجزیه و تحلیل ایجاد کنید

کامپوننت نمودار را بسازید

ایجاد جدول کاربران

جستجو برای کاربران

نتیجه

یک توسعه دهنده Pro React شوید

📁 کد را دانلود کنید

می‌توانید کد شروع و نهایی پروژه‌ای که می‌خواهیم بسازیم رادر اینجا دریافت کنید.

🛠️ ابزارهایی برای نصب

برای شروع ساخت داشبورد مدیریت، باید موارد زیر را داشته باشید:

Node.js روی رایانه شما نصب شده است.

همچنین باید یک ویرایشگر کد مانند Visual Studio Code داشته باشید.

در نهایت، باید یک حساب Github داشته باشید.

هنگامی که کد شروع را گرفتید و پوشه شروع را از حالت فشرده خارج کردید، آن را به Visual Studio Code بکشید، یک پنجره ترمینال را باز کنید و دستور را اجرا کنید:

 npm install

با این کار همه وابستگی های برنامه شما که در فایل package.json فهرست شده اند نصب می شوند.

پس از انجام این کار، می توانید با اجرای این دستور سرور توسعه خود را راه اندازی کنید:

 npm run dev

می‌توانید از localhost:3000 در مرورگر خود بازدید کنید تا برنامه خود را در حال اجرا و اجرا ببینید.

📀 چگونه یک پایگاه داده Postgres ایجاد کنیم

باطن برنامه شما از یک پایگاه داده Postgres تشکیل شده است. ما از Prisma برای تعامل با آن پایگاه داده استفاده خواهیم کرد و سرویس احراز هویت NextAuth خواهد بود.

برای ایجاد پایگاه داده Postgres جدید، به railway.app/new مراجعه کنید. شما می توانید یک پایگاه داده PostgreSQL به صورت رایگان بدون ایجاد حساب کاربری ایجاد کنید.

هنگامی که پایگاه داده ما ایجاد شد، روی آن کلیک کنید، سپس به تب Variables بروید و مقدار DATABASE_URL را کپی کنید.

اسکرین شات-2023-12-11-at-3.11.11-PM-2
صفحه متغیرها برای پایگاه داده Postgres در راه آهن

پس از آن، به فایل .env.example در پروژه خود بروید، نام آن را به .env تغییر دهید و آدرس پایگاه داده را به متغیر محیطی DATABASE_URL اضافه کنید.

✍️ نحوه راه اندازی Prisma Schema

اکنون که ما یک پایگاه داده کاملاً کاربردی داریم، باید آن را با Prisma متصل کنید. Prisma چیزی است که ما برای مدل سازی تمام داده های خود استفاده خواهیم کرد. این را می توانید در فایل schema.prisma ببینید.

فایل schema.prisma از اتصال به پایگاه داده، راه اندازی یک سرویس گیرنده Prisma و مدل سازی تمام داده های شما مراقبت می کند.

در ترمینال خود، دستور npx prisma db push اجرا کنید. این طرح شما را به پایگاه داده Railway Postgres هدایت می کند.

این دستور همچنین مشتری Prisma شما را تولید می کند که به شما امکان می دهد داده ها را در پایگاه داده خود با استفاده از Prisma دریافت و تغییر دهید.

نحوه استفاده از Prisma Client

در پوشه lib ، یک فایل prisma.ts ایجاد کنید. در این فایل، کلاینت Prisma را به عنوان یک متغیر سراسری به کل اپلیکیشن خود منتقل خواهید کرد.

 // lib/prisma.ts import { PrismaClient } from "@prisma/client"; declare global { var prisma: PrismaClient; } const client = globalThis.prisma || new PrismaClient(); if (process.env.NODE_ENV !== "production") globalThis.prisma = client; export default client;

اکنون می توانید به سادگی client در هر فایلی که نیاز به استفاده از Prisma دارد وارد کنید و داده ها را از پایگاه داده خود دریافت کنید.

🪝نحوه اتصال Prisma به NextAuth

مرحله بعدی اتصال Prisma به NextAuth است که مسئول احراز هویت کاربران ما خواهد بود.

در پوشه ریشه پروژه خود، یک پوشه pages ایجاد کنید که باید حاوی یک پوشه API باشد که باید حاوی یک پوشه auth باشد. در پوشه auth، فایل […nextauth].ts را قرار دهید.

ساختار پوشه شما باید به شکل زیر باشد:

 pages └ api └ auth └ [...nextauth].ts

اینجاست که NextAuth را راه اندازی می کنید، که باید با استفاده از آداپتور Prisma به Prisma متصل شود.

در این فایل می توانید کد زیر را Paste کنید:

 // pages/api/auth/[...nextauth].ts import prisma from "@/lib/prisma"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; import NextAuth, { AuthOptions } from "next-auth"; import GitHub from "next-auth/providers/github"; export const authOptions: AuthOptions = { adapter: PrismaAdapter(prisma), providers: [ GitHub({ clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, }), ], debug: process.env.NODE_ENV === "development", secret: process.env.NEXTAUTH_SECRET, callbacks: { async signIn() { return true; }, async redirect() { return "/"; }, }, }; export default NextAuth(authOptions);

برای احراز هویت کاربران با Github، از ارائه دهنده Github استفاده خواهید کرد که به شناسه مشتری و راز مشتری نیاز دارد.

برای بازیابی این موارد، باید به حساب Github خود وارد شوید و از این پیوند برای ایجاد یک Github OAuth App جدید استفاده کنید.

اسکرین شات-2023-12-11-at-4.16.40-PM
ثبت برنامه Github OAuth

یک نام برنامه منحصر به فرد مانند "داشبورد مدیریت" اضافه کنید. URL صفحه اصلی http://localhost:3000 خواهد بود، جایی که برنامه شما در حال توسعه است. اگر بخواهید این برنامه را اجرا کنید، این نشانی اینترنتی تولید شما خواهد بود.

URL بازگشت به تماس در فایل env. موجود است. مسیر catch-all که ما راه‌اندازی کرده‌ایم اجازه می‌دهد از این URL بازگشت به تماس استفاده شود.

در مرحله بعد، برنامه را برای دریافت شناسه مشتری خود ثبت کنید، که آن را روی متغیر محیطی GITHUT_CLIENT_ID تنظیم می کنید. یک راز کلاینت جدید ایجاد کنید، آن را کپی کنید و در زیر GITHUB_CLIENT_SECRET قرار دهید.

در نهایت، ما به یک راز نیاز داریم. به فایل env خود برگردید. من دستوری برای ایجاد یک رشته منحصر به فرد اضافه کرده ام:

 openssl rand -hex 32

این دستور را در ترمینال خود اجرا کنید، سپس رشته ایجاد شده را برای NEXT_AUTH_SECRET قرار دهید.

با همه متغیرهای محیطی که ارائه کرده‌ایم، Next Auth با موفقیت راه‌اندازی شد و می‌توان از آن برای احراز هویت کاربران و محافظت از مسیرها در سراسر برنامه استفاده کرد.

🧭 نحوه ساخت نوار ناوبری برنامه

همه اجزای برنامه ما در پوشه "components" قرار می گیرند.

بیایید یک مؤلفه Navbar در هر صفحه در برنامه اضافه کنیم. برای انجام این کار، می‌توانیم آن را به مؤلفه طرح‌بندی ریشه ( layout.tsx در پوشه برنامه) اضافه کنیم.

 // app/layout.tsx import Navbar from '@/components/Navbar'; import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; import { Suspense } from 'react'; import './globals.css'; const inter = Inter({ subsets: ['latin'] }) export const metadata: Metadata = { title: 'Admin Dashboard', } export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="en"> <body className={inter.className}> <Navbar /> {children} </body> </html> ) }

بیایید یک پیوند ورود به سیستم در مولفه Navbar ایجاد کنیم تا کاربران بتوانند خود را احراز هویت کنند.

در Navbar، از تابعی از NextAuth برای شروع فرآیند ورود استفاده کنید. متن "ورود به سیستم" را پیدا کنید و عملکرد را برای نمایش دسکتاپ و موبایل اجرا کنید.

 // components/Navbar.tsx // ... <Menu.Item> {({ active }) => ( <button className={classNames( active ? "bg-gray-100" : "", "flex w-full px-4 py-2 text-sm text-gray-700" )} onClick={() => signIn("github")} > Sign in </button> )} </Menu.Item> // ...

برای استفاده از این تابع signIn ، بالای مولفه Navbar اضافه کنید:

 import { signIn, signOut } from "next-auth/react";

انتخاب ورود به سیستم باید به یک صفحه میزبان GitHub هدایت شود تا کاربران بتوانند خود را احراز هویت کنند. اگر کاربران به درستی احراز هویت شوند، به صفحه اصلی باز خواهند گشت و وارد سیستم خواهند شد.

با اجرای دستور npx prisma studio می توانید تحلیل کنید و ببینید آیا کاربر جدیدی پس از ورود به سیستم ایجاد شده است یا خیر. استودیو Prisma به شما امکان می دهد داده های مدل، از جمله حساب ها، جلسات و کاربران را مشاهده و مدیریت کنید.

اسکرین شات-2023-12-11-at-4.22.30-PM
استودیو پریسما

نحوه نمایش اطلاعات حساب کاربری

مرحله بعدی نمایش اطلاعات حساب GitHub، مانند ایمیل و تصویر آواتار، به جای آواتار ساختگی است. برای این کار، به دلیل کتابخانه‌های خاصی، مانند مؤلفه‌های UI بدون سر، به یک مؤلفه مشتری نیاز داریم.

یک کامپوننت جدید در پوشه کامپوننت ها به نام Nav.tsx ایجاد کنید:

 // components/Nav.tsx import Navbar from "@/components/Navbar"; import { authOptions } from "@/pages/api/auth/[...nextauth]"; import { getServerSession } from "next-auth"; export default async function Nav() { const session = await getServerSession(authOptions); return <Navbar user={session?.user} />; }

در اینجا، ما جلسه فعلی کاربر وارد شده را دریافت می کنیم و آن را به مولفه Navbar در قسمت کاربر منتقل می کنیم.

در Navbar ، باید آن prop را دریافت کنیم و نوع آن را با استفاده از نوع Props اعلام کنیم.

 // components/Navbar.tsx import { Session } from "next-auth"; type Props = { user: Session["user"]; }; export default function Navbar({ user }: Props) { // ...

از آنجایی که Nav اکنون مولفه Navbar ما را بسته بندی می کند، Navbar را با Nav در فایل layout.tsx خود جایگزین کنید:

 // app/layout.tsx import Nav from '@/components/Nav'; // ... export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="en"> <body className={inter.className}> <Nav /> {children} </body> </html> ) }

همه فایل ها را ذخیره کنید و جلسه را در Nav وارد کنید. برنامه را به‌روزرسانی کنید و گزارش‌های مربوط به داده‌های کاربر را تحلیل کنید. ثبت نام کاربر در نوار ناوبری باید داده های کاربر را در کنسول مرورگر نمایش دهد.

برای نمایش داده های کاربر وارد شده به جای آواتار پیش فرض، از یک عبارت سه تایی در نوار ناوبری استفاده کنید.

اگر user.image وجود دارد، یک تصویر از "next/image" با کلاس ها و ویژگی های مناسب برگردانید.

همچنین، منبع را روی user.image ، ارتفاع و عرض را روی 32 و متن جایگزین را روی user.name یا "avatar" به عنوان بازگشتی تنظیم کنید.

اگر تصویر موجود نیست یا کاربر احراز هویت نشده است، از مؤلفه Avvvatars با مقدار "U" استفاده کنید.

 // components/Navbar.tsx // ... <Menu.Button className="flex rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-offset-2"> <span className="sr-only">Open user menu</span> {user?.image ? ( <Image className="h-8 w-8 rounded-full" src={user.image} height={32} width={32} alt={user?.name ?? 'avatar'} /> ) : ( <Avvvatars value={'U'} /> )} </Menu.Button> // ...

برای جزء آیتم های منو، کاربر را به عبارت سه تایی اضافه کنید و نمایش دکمه "خروج از سیستم" را فعال کنید. یک رویداد onClick را برای فراخوانی «خروج از سیستم» در هنگام کلیک اجرا کنید.

 // components/Navbar.tsx // ... <Menu.Items className="absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"> {user ? ( <Menu.Item> {({ active }) => ( <button className={classNames( active ? "bg-gray-100" : "", "flex w-full px-4 py-2 text-sm text-gray-700", )} onClick={() => signOut()} > Sign out </button> )} </Menu.Item> ) : ( // ...

این رویکرد واکشی داده ها بر روی سرور و ارسال آن به یک جزء مشتری را نشان می دهد. این یک روش موثر برای مدیریت داده های کاربر و نمایش آن ها در برنامه شما است.

🛡️ چگونه از مسیرها محافظت کنیم

آخرین مرحله در احراز هویت، محافظت از مسیرها است. ما یک داشبورد، یک صفحه کاربران (که صفحه اصلی است) و یک صفحه تجزیه و تحلیل داریم. صفحه تجزیه و تحلیل، که ما ایجاد خواهیم کرد، باید با رمز عبور محافظت شود تا فقط کاربران تأیید شده بتوانند به آن دسترسی داشته باشند.

برای محافظت از این مسیر، داده ها را با استفاده از تابع getServerSession روی سرور واکشی کنید. اما برای محافظت از مسیر /analytics ، باید آن را در پوشه برنامه ایجاد کنید. یک پوشه به نام analytics و داخل آن یک فایل page.tsx اضافه کنید.

ما باید از AnalyticsPage بر اساس وضعیت جلسه محافظت کنیم. اگر کاربر تأیید شده ای وجود نداشته باشد، ما به مسیر ورود به سیستم هدایت می شویم که /api/auth/sign-in است.

 // app/analytics/page.tsx import Analytics from "@/components/Analytics"; import { authOptions } from "@/pages/api/auth/[...nextauth]"; import { getServerSession } from "next-auth"; import { redirect } from "next/navigation"; export default async function AnalyticsPage() { const session = await getServerSession(authOptions); if (!session) { redirect("api/auth/signin"); } return <Analytics />; }

این الگوی اساسی برای محافظت از محتوا در داشبورد مدیریت ضروری است. با احراز هویت که اکنون پوشش داده شده است، می‌توانیم به ساخت رابط کاربری برویم.

📈 نحوه ایجاد صفحه تجزیه و تحلیل

ما از کتابخانه ای به نام Tremor برای ساختن نمودارها و نمودارها در صفحه تجزیه و تحلیل استفاده خواهیم کرد. Tremor به ما امکان می دهد داشبوردها را به سرعت ایجاد کنیم، اگرچه ما اطلاعات داشبورد را از پایگاه داده خود منبع نمی کنیم.

ما از اجزای Grid، Title و Flex برای چیدمان و استایل استفاده خواهیم کرد. ما همچنین از اجزای متریک و متن از Tremor برای نمایش آمار و برچسب‌ها در یک شبکه کارت استفاده خواهیم کرد.

 // components/Analytics.tsx "use client"; import Chart from "@/components/Chart"; import { BarList, Card, Flex, Grid, Metric, Text, Title } from "@tremor/react"; const app = [ { name: "/shop", value: 789 }, { name: "/product-features", value: 676 }, { name: "/about", value: 564 }, { name: "/login", value: 234 }, { name: "/downloads", value: 191 }, ]; const data = [ { category: "Mobile App", stat: "2,543", data: app, }, ]; export default function Analytics() { return ( <main className="p-4 md:p-10 mx-auto max-w-7xl"> <Grid numItemsSm={2} numItemsLg={3} className="gap-6"> {data.map((item) => ( <Card key={item.category}> <Title>{item.category}</Title> <Flex justifyContent="start" alignItems="baseline" className="space-x-2" > <Metric>{item.stat}</Metric> <Text>Total views</Text> </Flex> <Flex className="mt-6"> <Text>Pages</Text> <Text className="text-right">Views</Text> </Flex> <BarList data={item.data} valueFormatter={(number: number) => Intl.NumberFormat("us").format(number).toString() } className="mt-2" /> </Card> ))} </Grid> <Chart /> </main> ); }

📊 چگونه کامپوننت نمودار را بسازیم

پس از تنظیم شبکه بالا با نمودارهای میله ای، بیایید نمودار را در پایین با استفاده از مولفه AreaChart از Tremor تنظیم کنیم.

نمودار منطقه شامل داده های ماه های مختلف، مقایسه فروش و سود خواهد بود.

 // components/Chart.tsx "use client"; import { Card, AreaChart, Title, Text } from "@tremor/react"; const data = [ { Month: "Jan 21", Sales: 2890, Profit: 2400, }, { Month: "Feb 21", Sales: 1890, Profit: 1398, }, { Month: "Jan 22", Sales: 3890, Profit: 2980, }, ]; export default function Chart() { return ( <Card className="mt-8"> <Title>Performance</Title> <Text>Comparison between Sales and Profit</Text> <AreaChart className="mt-4 h-80" data={data} categories={["Sales", "Profit"]} index="Month" colors={["indigo", "fuchsia"]} valueFormatter={(number: number) => `$ ${Intl.NumberFormat("us").format(number).toString()}` } yAxisWidth={60} /> </Card> ); }

👥 نحوه ایجاد جدول کاربران

اکنون که از صفحه تجزیه و تحلیل خود مراقبت کرده ایم، بیایید به جدول کاربران بپردازیم.

این جدول کاربران پایگاه داده Postgres ما را نمایش می دهد. ما همه کاربرانی را که از سرویس گیرنده Prisma استفاده می کنند واکشی و پرس و جو می کنیم و نشان می دهیم که چگونه کاربران را بر اساس نام یا فیلدهای دیگر جستجو کنیم.

ما با ساختن یک جدول ساده با کمک اجزای Tremor در کامپوننت UsersTable شروع می کنیم. اگر با عناصر جدول HTML آشنا هستید، این باید برای شما بسیار آشنا به نظر برسد.

ما برای هر یک از کاربران ردیف هایی برای name ، email و مقادیر created_at ایجاد می کنیم و آن مقادیر را در بدنه جدول نمایش می دهیم:

 // components/UsersTable.tsx import { User } from "@prisma/client"; import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, } from "@tremor/react"; type Props = { users: User[]; }; export default function UsersTable({ users }: Props) { return ( <Table> <TableHead> <TableRow> <TableHeaderCell>Name</TableHeaderCell> <TableHeaderCell>Email</TableHeaderCell> <TableHeaderCell>Created At</TableHeaderCell> </TableRow> </TableHead> <TableBody> {users.map((user) => ( <TableRow key={user.id}> <TableCell>{user.name}</TableCell> <TableCell>{user.email}</TableCell> <TableCell> {new Intl.DateTimeFormat("en-US").format(user.createdAt)} </TableCell> </TableRow> ))} </TableBody> </Table> ); }

🔎 نحوه جستجوی کاربران

برای اینکه جدول ما قابل جستجو باشد، به صفحه اصلی باز می‌گردیم و رابط کاربری اصلی را برای مؤلفه جستجو می‌سازیم.

 // components/Search export default function Search({ query }: Props) { return ( <div className="relative mt-5 max-w-md"> <label htmlFor="search" className="sr-only"> Search </label> <div className="rounded-md shadow-sm"> <div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"> <SearchIcon className="mr-3 h-4 w-4 text-gray-400" /> </div> <input type="text" name="search" autoComplete="off" id="search" className="h-10 block w-full rounded-md border border-gray-200 pl-9 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" placeholder="Search by name..." onChange={(event) => handleSearch(event.target.value)} defaultValue={query} /> </div> </div> ); }

از آنجایی که به طور پیش‌فرض اجزای سرور کاربران Next.js وجود دارد، می‌توانیم از وضعیت URL برای شروع درخواست‌ها استفاده کنیم.

در یک تابع جدید به نام handleSearch ، می‌توانیم URL را با گفت ن یک پارامتر query به نام q به‌روزرسانی کنیم و درخواستی را که کاربر تایپ کرده در ورودی به عنوان مقدار تنظیم کنیم.

این بدان معناست که وقتی کاربر ورودی را تایپ می کند، عبارت جستجو به URL اضافه می شود.

 // components/Search.tsx import { usePathname, useRouter } from "next/navigation"; import { useTransition } from "react"; type Props = { query?: string; }; export default function Search({ query }: Props) { const router = useRouter(); const pathname = usePathname(); const [isPending, startTransition] = useTransition(); function handleSearch(value: string) { const params = new URLSearchParams(window.location.search); if (value) { params.set("q", value); } else { params.delete("q"); } startTransition(() => { router.replace(`${pathname}?${params.toString()}`); }); } // ...

در مؤلفه سرور خود، app.tsx ، از پارامترهای جستجو (که به عنوان پایه در اجزای صفحه ارائه می شوند) برای پرس و جو از پایگاه داده خود با Prisma استفاده می کنیم.

می‌توانیم روش findMany را برای جستجوی کاربران بر اساس name و email با استفاده از فیلتر «where» تغییر دهیم. همچنین می‌توانیم با استفاده از mode: insensitive این کار را به روشی غیر حساس انجام دهیم.

 // app/page.tsx // ... type Props = { searchParams: { q?: string; }; }; export default async function Home({ searchParams }: Props) { const query = searchParams.q; const users = await prisma.user.findMany({ where: { name: { contains: query, mode: "insensitive", }, email: { contains: query, mode: "insensitive", }, }, }); // ...

در نهایت، ما از قلاب useTransition برای تغییر URL به روشی کاربردی استفاده می کنیم.

در مولفه Search ، می‌توانید یک چرخش بارگذاری را به انتهای ورودی خود اضافه کنید تا به کاربر بگویید که در حال تغییر URL هستیم.

 // components/Search.tsx // ... {isPending && ( <div className="absolute right-0 top-0 bottom-0 flex items-center justify-center"> <RotateCwIcon className="animate-spin -ml-1 mr-3 h-5 w-5 text-gray-700" /> </div> )} </div>

این رویکرد تغییر وضعیت URL را با هر ضربه کلید به روشی کارآمد نشان می دهد، به ویژه هنگام استفاده از اجزای سرور در Next.js.

نتیجه

در پایان، ساخت این داشبورد مدیریت جنبه‌های بسیاری را پوشش می‌دهد، از تنظیم احراز هویت با NextAuth و Prisma تا ایجاد یک رابط کاربر پسند با Tremor.

این ابزارها و تکنیک ها راهی جامع برای ایجاد داشبوردهای انعطاف پذیر و جذاب از نظر بصری ارائه می دهند. با خیال راحت از این داشبورد مدیریت در پروژه های خود استفاده کنید.

از اینکه دنبال کردید متشکرم و امیدوارم این راهنما مفید بوده باشد!

🏆 یک توسعه دهنده React حرفه ای شوید

به دنبال منبع نهایی برای یادگیری React از ابتدا تا انتها هستید؟

معرفی: React Bootcamp

بوت کمپ دارای هر منبعی است تا به شما در موفقیت در React کمک کند:

🎬 200+ ویدیوی عمیق

🕹️ بیش از 100 چالش عملی React

🛠️ 5+ پروژه نمونه کارها چشمگیر

📄 بیش از 10 برگه تقلب ضروری React

🥾 یک بوت کمپ کامل Next.js

🖼️ مجموعه کاملی از ویدیوهای متحرک

روی زیر کلیک کنید تا React Bootcamp را برای خودتان امتحان کنید.

برای پیوستن <a href= به React Bootcamp کلیک کنید" width="1105" height="394" loading="lazy">
برای شروع کلیک کنید

خبرکاو

ارسال نظر




تبليغات ايهنا تبليغات ايهنا

تمامی حقوق مادی و معنوی این سایت متعلق به خبرکاو است و استفاده از مطالب با ذکر منبع بلامانع است