ساخت اپلیکیشن یادداشت با React و FaunaDB – از صفر تا صد
هم اینک در سال 2020 میلادی هستیم و روشهای زیادی برای ساخت وباپلیکیشنها وجود دارد. در این مقاله به بررسی روش ساخت اپلیکیشن یادداشت با React و FaunaDB میپردازیم و به این ترتیب با یک رویکرد ساخت سریع اپلیکیشنهای واکنشگرا به روشی جذاب آشنا خواهیم شد.
چه چیزی میسازیم؟
در این راهنما میخواهیم یک اپلیکیشن یادداشت بسازیم، زیرا مثالی خوبی برای نشان دادن شیوه کار React و FaunaDB در کنار هم است.
برای ثبت یادداشت باید کارکردهای CRUD یعنی ایجاد، خواندن، بهروزرسانی و حذف (create ،read ،update و delete) را پیادهسازی کنیم که اساس هر اپلیکیشن مدرنی محسوب میشود.
میخواهیم یک معماری داشته باشیم که کاربرانمان بتوانند یادداشت جدیدی در آن ایجاد کنند، یادداشتهای قبلی را ویرایش نمایند و همچنین یادداشتها را از پایگاه داده واکشی کرده و یا حذف نمایند.
سرعت، دقت و امنیت بسیار مهم هستند و از این رو باید بتوانیم مستقیماً از مرورگر با پایگاه داده تعامل پیدا کنیم و از نوشتن و خواندن منسجم در پایگاه داده مطمئن باشیم، یعنی تراکنشهای تضمینشدهای داشته باشیم. به همین جهت گزینههای FaunaDB و React را برای این پروژه انتخاب کردهایم.
چرا از FaunaDB استفاده میکنیم؟
FaunaDB سریع است، به خوبی مقیاسبندی میشود و کار با آن آسان است. با این که داشتن این مزیتها خوب است، اما بهترین مزیت در مورد انتخاب یک ارائهدهنده ابریِ پایگاه داده میزان سهولت آغاز به کار و اجرای آن است. بدین ترتیب به جای صرف ساعتها وقت برای راهاندازی و پشتیبانی از پایگاه داده به سادگی با استفاده از FaunaDB همه این موارد در اختیار توسعهدهنده قرار میگیرد. هر چه تلاش کمتری برای ایجاد زیرساخت صرف کنیم، زمان و انرژی بیشتری برای تمرکز روی ساخت عملی اپلیکیشن خود خواهیم داشت.
بدین ترتیب دیگر لازم نیست در مورد انسجام، مقیاسبندی، تهیه کپی، افزونگی دادهها و مواردی از این دست تفکر کنیم. FaunaDB همه این وظایف را بر عهده میگیرد. به این ترتیب به جای پرداختن به تهیه زیرساخت و فرایند راهاندازی میتوانیم روی هسته مرکزی اپلیکیشن تمرکز کنیم. FaunaDB از پروتکل Calvin (+) برای نگهداری چندین کپی کامل و سازگار از دادهها استفاده میکند که Replica نام دارد. بدین ترتیب امکان خواندن و نوشتن روی هر گره را پیدا میکنیم. هر رپلیکا شامل چندین گره با آگاهی از مکان جغرافیایی خود است که هر یک دارای یک پارتیشن از مجموعه دادههای کامل در یک محیط لوکال منفرد هستند.
همچنین FaunaDB از احراز هویت از طریق کلیدهای دسترسی، کنترلهای دسترسی مبتنی بر خصوصیت، مجوزهای سطح وهله نیتیو، TLS/SSL برای پایگاههای داده و کلاینتها، جداسازی client/tenant از طریق سلسلهمراتب پایگاه داده، اولویتبندی بارهای کاری و همچنین توکنهای دسترسی امن برای دسترسی مستقیم کلاینت به پایگاه داده پشتیبانی میکند. کلاسترهای client/tenant نیازمند احراز هویت هستند و امکان این که به صورت تصادفی حفاظت نشده رها شوند، وجود ندارد.
چرا از ریاکت استفاده میکنیم؟
ریاکت خود را به عنوان یک کتابخانه فرانتاند پیشرو تثبیت کرده است. نکته مهمتر این که کار با ریاکت و توسعه اپلیکیشن با ریاکت کاملاً آسان و جذاب است. البته علاوه بر ریاکت چندین راهحل مناسب دیگر مانند Vue ،Angular، Svelte و غیره برای این پروژه وجود دارند، اما تا زمانی که کارها به پیش میروند مهم نیست که از کدام کتابخانه استفاده میکنید. بدون هر گونه توضیح اضافه به سراغ توسعه اپلیکیشن یادداشت خود میرویم.
شروع
از آنجا که میخواهیم از React و FaunaDB استفاده کنیم، به طور طبیعی باید Node را نصب کنیم.
پیشنیازها
- یک ادیتور متنی (استفاده از ویژوال استودیو کد پیشنهاد میشود)
- نصب Node.js (میتوانید از طریق وبسایت (+) یا ترمینال نصب کنید)
- ترمینال مبتنی بر یونیکس
- مرورگر وب
اسکریپت create-react-app
ترمینال خود را باز کرده و با اجرای دستور زیر با استفاده از اسکریپت create-react-app یک اپلیکیشن جدید ریاکت ایجاد کنید:
npx create-react-app react-faunadb-note-app && cd react-faunadb-note-app && start
اکنون که پروژه راهاندازی شد، پوشهها را ایجاد میکنیم. باید دایرکتوریهای زیر را داشته باشیم:
- config - همه پایگاههای داده مرتبط با منطق در اینجا قرار میگیرد.
- Components - موارد مرتبط با ریاکت در آن جای میگیرد.
- api - متدهای واکشی، ویرایش و حذف یادداشتها را در خود جای میدهد.
راهاندازی FaunaDB
به صفحه ثبت نام وبسایت FaunaDB (+) بروید و به عنوان یک کاربر جدید ثبت نام کنید. این کار رایگان است.
زمانی که حساب خود را ایجاد کردید، یک پایگاه داده ایجاد نمایید. ما نام پایگاه خود را notes_app میگذاریم:
اکنون که پایگاه دادهمان ایجاد شد، میتوانیم کلید دسترسی بسازیم. از این کلیدها برای اتصال و احراز هویت در پایگاه داده استفاده میشود. به این ترتیب میتوانیم کنترل کنیم که چه کسی دسترسی خواندن و نوشتن به پایگاه داده دارد. اما پیش از آن که این کار را انجام دهیم، باید یک «نقش» (role) برای پایگاه داده خود ایجاد کنیم. گزینههای نقش در این منو قرار دارند:
console → app → security → roles → new role
سپس به ادامه کار پرداخته و کلید پایگاه داده را ایجاد میکنیم. از این کلید برای دسترسی یافتن به پایگاه داده استفاده خواهیم کرد:
console → app → security → keys → new key
زمانی که روی Save کلیک کنید، باید کلید FaunaDB را ببینید.
نکتهای که باید به خاطر داشته باشید، این است که این کلید دسترسی admin دارد، یعنی اگر کلید نشت یابد، یک خطر امنیتی مهم رخ میدهد. کار خود را با کلیدهای کماهمیتتر آغاز میکنیم.
کلید را به ادیتور متنی یا یک مکان امن کپی کنید. در ادامه به آن نیاز خواهیم داشت. ما میخواهیم از FaunaDB به عنوان یک پایگاه داده ذخیرهسازی سند استفاده کنیم. البته گزینههای دیگری نیز وجود دارند. از آنجا که هماینک در کنسول هستیم، کلکسیون notes را نیز ایجاد میکنیم. منظور از کلکسیون (collection) گروهی از اسناد است. در این پروژه هر یادداشت یک سند است.
زمانی که کلکسیون ایجاد شد، FaunaDB به صورت پیشفرض اقدام به اندیس کردن سند میکند.
اندیسها ساختارهای ذخیرهسازی هستند که از سوی سیستم پایگاه داده برای تسهیل بازیابی مؤثر زیرمجموعهای از دادهها استفاده میشوند. طراحی اسکیمای کارآمد FaunaDB موجب شده که از هر دو مزیت پشتیبانی درجه اول از مدلسازی رابطهای و اندیسهای متریال پشتیبانی کند.
ایجاد ارتباط بین ریاکت و یک وهله از FaunaDB
اکنون که همه چیز در سمت FaunaDB آماده است، به بررسی بخش ریاکت میپردازیم.
نصب وابستگیها
باید تا حد امکان تلاش کنیم از کدهای موجود، استفاده مجدد داشته باشیم، چون این کار موجب آسانتر شدن کارها و افزایش سرعت توسعه میشود. در این بخش از چند کتابخانه محبوب استفاده میکنیم. اپلیکیشن ما وابستگیهای زیر را دارد:
- Faunadb – درایور جاوا اسکریپت FaunaDB
- antd - زبان طراحی UI در کلاس سازمانی و کتابخانه رابط کاربری ریاکت
- react-toastify – موجب تسهیل ارسال نوتیفیکیشن ریاکت میشود.
ایجاد فایل env.
از آنجا که نمیخواهیم کلیدها و توکنهایمان با وارد شدن درون ریپازیتوری به بیرون نشت یابند، باید از فایلهای env. استفاده کنیم.
در ادامه فایل env. را به gitignore. اضافه میکنیم. env.example. باید بدون مقدار به ریپازیتوری پوش شود.
مطمئن شوید که YOURKEYHERE را با کلید FaunaDB عوض کردهاید. سپس سرور را ریاستارت کنید. به این ترتیب از هم اکنون از طریق مقدار process.env.REACT_APP_FAUNADB_KEY به کلید FaunaDB دسترسی داریم. هم اینک معماری پروژه ما باید چیزی مانند زیر باشد:
ایجاد ارتباط اولیه با FaunaDB
تا به اینجا مسیری نسبتاً طولانی آمدهایم و اینک زمان آن فرا رسیده است که یک ارتباط با پایگاه داده خود بگیریم. بنابراین یک فایل به نام db.js درون دایرکتوری config میسازیم:
پس از برقراری ارتباط میتوانیم شروع به کوئری زدن به FaunaDB بکنیم. آیا دایرکتوری api را که قبلاً متذکر شدیم، به خاطر دارید؟ این همان جایی است که همه منطق مرتبط با کوئریها را در آن قرار میدهیم. به این ترتیب میتوانیم چیزی مانند ()fetchAllNotes را درون کامپوننت ریاکت فراخوانی کنیم. این کار را به این جهت انجام میدهیم که دغدغهها را هم جدا کنیم تا خواندن و درک کامپوننت ریاکت آسان شود.
نوشتن کوئریهای FaunaDB
این اپلیکیشن یادداشت به کاربران اجازه میدهد که یادداشتها را ایجاد کرده، ویرایش و حذف کنند و یا همه آنها را از سرور واکشی نمایند. کار را با واکشی همه یادداشتها از کلکسیون آغاز میکنیم.
واکشی همه یادداشتها
ممکن است فکر کنید کد فوق حجم بالایی دارد، اما کارکرد آن نسبتاً ساده است. در ادامه این کارکرد را به تفصیل شرح میدهیم:
- ابتدا پایگاه داده FaunaDB و وهله کوئری ایمپورت میشود.
- با استفاده از اندیس notes به همه یادداشتها کوئری میزنیم. این کوئری همه ref-ها را بازگشت میدهد که روی آن نگاشت کرده و نتایج را بازگشت میدهیم.
- در صورت بروز خطای شبکه آن خطا را دریافت کرده و هشداری را لاگ میکنیم این حالت در زمانی که میخواهیم بازخوردی به کاربر بدهیم مفید خواهد بود.
توجه کنید که ما از Promise-های ناهمگام استفاده میکنیم. اگر این مفهوم برای شما جدید است میتوانید راهنمای زیر را مطالعه کنید:
ویرایش کردن یک یادداشت
ویرایش کردن رکوردهای FaunaDB آسان است. تنها کاری که باید انجام دهیم فراخوانی کوئری Update با ID مرجع و مقدار جدید است.
این کوئری را درون یک تابع قرار دادیم که دو آرگومان میگیرد. یکی از آرگومانها noteId است که میخواهیم ویرایش کنیم و دیگری مقدار متن جدید است.
حذف کردن یک یادداشت
حذف کردن یک یادداشت نیز مشابه ویرایش کردن آن است. کافی است کوئری Delete را با ID مرجع یادداشت فراخوانی کنیم.
ایجاد یک یادداشت
در نهایت کد کوئری FaunaDB برای افزودن یک یادداشت جدید به کلکسیون به صورت زیر است:
توجه کنید که FaunaDB کوئریهای خود را به صورت منطقی مانند q.Create ،q.Delete ،q.Update و غیره نامگذاری کرده است.
اکسپورت کردن کوئریها
اکنون که نوشتن کد کوئریها را به پایان بردیم، نوبت آن رسیده است که کوئریها را اکسپورت کنیم تا بتوانیم از آنها درون کامپوننتهای ریاکت استفاده کنیم. در ادامه فایلی به نام index.js درون دایرکتوری api ایجاد میکنیم:
کد فوق به ما امکان میدهد که به جای نوشتن خطوط کدهای ایمپورت، این کار را در یک خط به صورت زیر انجام دهیم:
import { getAllNotes, deleteNote, editNote, createNote } from ‘./api’
فراخوانی کوئریهای FaunaDB با ریاکت
تنها کاری که باقی مانده است، فراخوانی کردن کوئریهای FaunaDB و رندر کردن نتایج است. کار را با باز کردن فایل App.js و نوشتن کد زیر در آن آغاز میکنیم:
در کد فوق کارهای زیر انجام میشوند:
- کوئریهای FaunaDB از دایرکتوری api ایمپورت میشوند.
- با استفاده از قلاب useState یک «حالت» (State) برای یادداشتها ایجاد میشود.
اگر در مورد قلابهای ریاکت اطلاعات کمی دارید، پیشنهاد میکنیم مطلب زیر را مطالعه کنید:
اعتبارسنجی فرم با قلابهای React — به زبان ساده
- در ادامه درون قلاب useEffects اقدام به فراخوانی getAllNotes میکنیم. این قلاب بیدرنگ پیش از نصب کامپوننت فراخوانی میشود.
نتیجه بازگشتی کوئری به صورت زیر است. نتیجه را به صورت حالت notes ذخیره کرده و با ریاکت رندر میکنیم:
شاید کنجکاو باشید که این timestamp-ها به چه چیزی مربوط هستند. FaunaDB این موارد را ردگیری میکند، چون دارای یک نسخهبندی داخلی است. شما میتوانید در صورت نیاز سابقه هر یادداشت را نیز کوئری کنید.
ایجاد یادداشتها
در این بخش فایلهای زیر را در دایرکتوری components ایجاد میکنیم:
- NoteForm.js – این فایل برای ایجاد یادداشتهای جدید استفاده میشود.
- NoteList.js - همه یادداشتها را رندر کرده و کارکردهای مرتبط با یادداشتها مانند ویرایش و حذف را نمایش میدهد.
- Index.js – برای ایمپورت و اکسپورت استفاده میشود.
در ادامه ابتدا فایل NoteForm.js را ایجاد میکنیم:
توجه کنید که در انتهای فایل کامپوننت NoteForm را درون کامپوننت مرتبه بالاتر (HOC) به نام Form با طراحی Ant قرار دادهایم. بدین ترتیب میتوانیم از تزریق استفاده کنیم و به prop فرم از درون کامپوننت NoteForm دسترسی پیدا میکنیم. مشخصه from شامل متدهایی برای اعتبارسنجی فرم است. بدین منظور از متدهای getFieldDecorator ،validateFields و resetFields استفاده میکنیم.
پیادهسازی مدیریت تحویل فرم
در این بخش به اعتبارسنجی فرم میپردازیم. اگر هیچ خطایی در فرم نباشد و دستکم یک کاراکتر در آن وجود داشته باشد، فرم را تحویل میدهیم و با کوئری زدن به وهله FaunaDB میخواهیم که این یادداشت را ذخیره کند. توجه کنید که ما از prop-های notes و setNotes استفاده میکنیم. ما باید این موارد را از App.js استفاده کنیم. اگر بیشتر دقت کنید متوجه میشوید که مقادیر را از اشیای props و form میگیریم. اکنون اقدام به ایمپورت کامپوننتها در index.js میکنیم تا بتوانیم آنها را به شیوهای آسان در پروژه ایمپورت کنیم.
استایلبندی
ما برای اپلیکیشن خود استایلهای زیر را ایجاد کردهایم. محتوای زیر را در فایل App.css کپی کنید. البته میتوانید بسته به سلیقه خود هر نوع تغییری که مطلوب میدانید را روی آن اعمال کنید:
استفاده از کامپوننت NoteForm
اینک زمان آن فرا رسیده است که از کامپوننت NoteForm استفاده کنیم. این کامپوننت را در فایل App.js ایمپورت کنید:
فراموش نکنید که props را به کامپوننت NoteForm ارسال کنید. اینک باید در مرورگر نتیجهای مانند تصویر زیر داشته باشید:
اینک فرم کار میکند، اما نتایج هنوز رندر نمیشوند. این مشکل را نیز اصلاح میکنیم. فایل کامپوننت NoteList.js را باز کرده و کد زیر را در آن بنویسید:
به این ترتیب همه یادداشتها را نگاشت کرده و رندر میکنیم. برای هر یادداشت شنوندههای رویدادی اضافه میکنیم تا ویرایش شدن محتوا و حذف شدن یادداشتها را متوجه شویم. NoteList را در App ایمپورت کرده و آن را زیر کامپوننت NoteForm قرار دهید:
همچنین پیادهسازی متدهای handleRemove و handleEdit را فراموش نکنید. آنها را به صورت prop به کامپوننت NoteList ارسال کنید. اینک مرورگر را باز کرده و چیزی در NoteForm نوشته و اینتر را بزنید. به این ترتیب نتیجهای مانند زیر میبینید:
اینک اگر کلکسیون FaunaDB را بررسی کنیم، میبینیم که یادداشتهای جدیدی درج شدهاند. تلاش کنید یادداشتهای جدیدی ایجاد کرده و آنها را ویرایش یا حذف کنید.
اگر مشکلی پیش نیامد به این معنی است که ما پروژه خود را با موفقیت اجرا کردهایم.
موارد اختیاری: افزودن نوتیفیکیشن Toast
اگر میخواهید زمانی که کاربر یادداشتها را درج یا حذف میکند، نوتیفیکیشنهایی روی صفحه ظاهر شوند، به روش زیر عمل کنید:
در کد فوق:
- ابتدا استایل ها را ایمپورت کرده ToastContainer را نیز از کتابخانه react-toastify ایمپورت کردهایم.
- ToastContainer درون متد return قرار گرفته است. بدین ترتیب به نوتیفیکیشن Toast دسترسی مییابیم. اکنون میتوانیم با فراخوانی toast.success(‘message here’) یا toast.error(‘error message’) از هر جایی در اپلیکیشن نوتیفیکیشن بسازیم. با قرار دادن پیامهای Toast در متد handleRemove کد فوق را تست کنید. فراموش نکنید که هر جا میخواهید از آن استفاده کنید، باید متد toast را از پکیج ایمپورت کنید.
import { toast } from 'react-toastify';
اکنون اگر روی آیکون حذف کلیک کنید، یک toast میبینید:
برای دسترسی به کد کامل این پروژه به این ریپوی گیتهاب (+) بروید.
نکته مهم: با توجه به مقاصد آموزشی این راهنما، این اپلیکیشن به همه کاربران اجازه میدهد که به وبسایت دسترسی یابند و یادداشتهایی ایجاد کرده و بخوانند. در سناریوهای واقعی این وضعیت به دلایل امنیتی مطلوب نیست. به طور معمول باید اپلیکیشن را در پشت یک صفحه امنیتی لاگین قرار دهیم که تابع لاگین FaunaDB یا راهکارهای دیگر را پیادهسازی میکند.
سخن پایانی
از این که این راهنما را تا به انتهای پیگیری کردید متشکریم. امیدواریم با مطالعه این مقاله موارد جدیدی آموخته باشید. هر گونه نظر و پیشنهاد خود را میتوانید در بخش نظرات این نوشته با ما و دیگر خوانندگان مجله در میان بگذارید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- مجموعه آموزشهای برنامهنویسی
- آموزش ری اکت (React) — مجموعه مقالات مجله فرادرس
- ری اکت (React) — راهنمای جامع برای شروع به کار
- هشت ترفند مفید برای توسعه اپلیکیشن های React — راهنمای کاربردی
- طراحی احراز هویت مقدماتی با React — به زبان ساده
==