راهنمای جامع React (بخش نهم-پایانی) — از صفر تا صد
اکوسیستم شکلگرفته پیرامون ریاکت بسیار بزرگ است. در این مقاله که آخرین مقاله از این سری محسوب میشود، 4 مورد از محبوبترین پروژهها بر مبنای React یعنی React Router ،Redux ،Next.js و Gatsby را معرفی میکنیم. همچنین بخش قبلی این مجموعه مطلب آموزشی را میتوانید از طریق کلیک روی لینک زیر مطالعه کنید:
React Router
«مسیریاب ریاکت» (React Router) کتابخانه پیشفرض مسیریابی برای ریاکت محسوب میشود و یکی از محبوبترین پروژهها است که بر مبنای ریاکت ساخته شده است. ریاکت در هسته مرکزی خود یک کتابخانه بسیار ساده است و هیچ نکتهای در خصوص مسیریابی را شامل نمیشود.
مسیریابی یک اپلیکیشن تکصفحهای است که روشی برای معرفی برخی ویژگیهای جدید در زمینه ناوبری در اپلیکیشن از طریق لینکها محسوب میشود؛ این روش در زمینه وباپلیکیشنها کاملاً نرمال تلقی میشود:
- زمانی که به صفحههای مختلفی مراجعه میکنید، آدرس نمایش یافته در مرورگر باید تغییر پیدا کند.
- «لینک دهی عمیق» (Deep linking) باید کار کند، یعنی اگر مرورگر به یک لینک هدایت شود، اپلیکیشن باید همان ویو را که در زمان ایجاد URL ایجاد شده بود ارائه کند.
- دکمههای عقب و جلوی مرورگر باید مطابق انتشار عمل کنند.
در واقع مسیریاب ریاکت روشی برای ایجاد ارتباط بین ناوبری اپلیکیشن و ویژگیهای ناوبری ارائه شده از سوی مرورگر میسازد: یعنی ترکیبی از نوار آدرس مرورگر و دکمههای ناوبری اپلیکیشن. مسیریاب ریاکت روشی برای کدنویسی ارائه میکند که به وسیله آن کامپوننتهای خاصی از اپلیکیشن تنها در صورتی نمایش مییابند که مسیر مورد نظر با آن چه تعریف شده مطابقت داشته باشد.
نصب
با استفاده از npm میتوانید مسیریاب را با دستور زیر نصب کنید:
npm install react-router-dom
با استفاده از Yarn با دستور زیر روتر ریاکت را نصب کنید:
yarn add react-router-dom
انواع مسیریابی
مسیریاب ریاکت دو نوع مختلف از مسیریابی ارائه میکند:
- BrowserRouter
- HashRouter
یک روش URL-های کلاسیک میسازد و دیگری URL-هایی با هش ایجاد میکند:
https://application.com/dashboard/* BrowserRouter */ https://application.com/#/dashboard /* HashRouter */
این که باید از کدام یک استفاده کرد عموماً از سوی مرورگرهایی که باید پشتیبانی شوند تعیین میشود. BrowserRouter از History API (+) استفاده میکند که نسبتاً جدید است و در IE9 و نسخههای قدیمیتر از آن پشتیبانی نمیشود. اگر ضرورتی برای نگرانی در مورد مرورگرهای قدمی ندارید، این گزینه پیشنهاد خوبی محسوب میشود.
کامپوننتها
3 کامپوننت وجود دارند که هنگام کار با مسیریاب ریاکت با آنها بیشتر سر و کار خواهید داشت و به شرح زیر هستند:
- BrowserRouter که به صورت معمول Router نوشته میشود.
- Link
- Route
BrowserRouter همه کامپوننتهای Route را دربر میگیرد. کامپوننتهای Link همان طور که میتوان تصور کرد، آنهایی هستند که برای تولید لینک برای مسیرها استفاده میشوند. کامپوننتهای Route مسئول نمایش، یا مخفی سازی کامپوننتهایی که در خود جای دادهاند هستند.
BrowserRouter
در ادامه مثال سادهای از کامپوننت BrowserRouter را میبینید. آن را از react-router-dom ایمپورت کنید و برای پوشش همه اپلیکیشن از آن بهره بگیرید:
1import React from 'react'
2import ReactDOM from 'react-dom'
3import { BrowserRouter as Router } from 'react-router-dom'
4ReactDOM.render(
5 <Router>
6 <div>
7 <!-- -->
8 </div>
9 </Router>,
10 document.getElementById('app')
11)
یک کامپوننت تنها میتواند یک عنصر فرزند داشته باشد و از این رو همه آن چیزهایی که پوشش میدهد در یک عنصر div اضافه میشوند.
Link
کامپوننت Link برای آغاز مسیرهای جدید استفاده میشود. آن را از react-router-dom ایمپورت کنید. میتوانید کامپوننتهای Link را برای اشاره به مسیرهای مختلف با استفاده از خصوصیت to اضافه کنید:
1import React from 'react'
2import ReactDOM from 'react-dom'
3import { BrowserRouter as Router, Link } from 'react-router-dom'
4ReactDOM.render(
5 <Router>
6 <div>
7 <aside>
8 <Link to={`/dashboard`}>Dashboard</Link>
9 <Link to={`/about`}>About</Link>
10 </aside>
11 <!-- -->
12 </div>
13 </Router>,
14 document.getElementById('app')
15)
Route
اینک نوبت اضافه کردن کامپوننت Route در قطعه کد فوق است تا همه چیز عملاً آن چنان که میخواهیم کار کند:
1import React from 'react'
2import ReactDOM from 'react-dom'
3import { BrowserRouter as Router, Link, Route } from 'react-router-dom'
4const Dashboard = () => (
5 <div>
6 <h2>Dashboard</h2>
7 ...
8 </div>
9)
10const About = () => (
11 <div>
12 <h2>About</h2>
13 ...
14 </div>
15)
16ReactDOM.render(
17 <Router>
18 <div>
19 <aside>
20 <Link to={`/`}>Dashboard</Link>
21 <Link to={`/about`}>About</Link>
22 </aside>
23 <main>
24 <Route exact path="/" component={Dashboard} />
25 <Route path="/about" component={About} />
26 </main>
27 </div>
28 </Router>,
29 document.getElementById('app')
30)
برای آشنایی بیشتر میتوانید مثال موجود در این لینک (+) را بررسی کنید. زمانی که مسیری با / مطابقت مییابد، اپلیکیشن کامپوننت Dashboard را نمایش میدهد.
زمانی که مسیری از طریق کلیک کردن روی لینک «About» به about/ تغییر پیدا میکند، کامپوننت Dashboard حذف میشود و کامپوننت About در DOM درج میشود.
به خصوصیت exact دقت کنید. بدون وجود این خصوصیت، ”/”=path میتواند با about. مطابقت یابد و از این رو / در مسیر جای میگیرد.
مطابقت با مسیرهای چندگانه
شما میتوانید مسیری داشته باشید که به سادگی با استفاده از یک regex به چندین مسیر پاسخ دهد، زیرا path میتواند یک رشته «عبارتهای منظم» (Regular Expresions) باشد:
1<Route path="/(about|who)/" component={Dashboard} />
رندرینگ درونخطی
به جای تعیین مشخصه component روی Route میتوان یک prop به نام render را نیز تعیین کرد:
1<Route
2 path="/(about|who)/"
3 render={() => (
4 <div>
5 <h2>About</h2>
6 ...
7 </div>
8 )}
9/>
مطابقت پارامتر مسیر دینامیک
شما قبلاً شیوه استفاده از مسیرهای استاتیک را به صورت زیر مشاهده کردهاید:
1const Posts = () => (
2 <div>
3 <h2>Posts</h2>
4 ...
5 </div>
6)
7//...
8<Route exact path="/posts" component={Posts} />
در ادامه روش مدیریت مسیرهای دینامیک را بررسی میکنیم:
1const Post = ({match}) => (
2 <div>
3 <h2>Post #{match.params.id}</h2>
4 ...
5 </div>
6)
7//...
8<Route exact path="/post/:id" component={Post} />
در کامپوننت Route میتوانید پارامترهای دینامیک را در match.params بررسی کنید.
Match در مسیرهایی که به صورت درونخطی رندر میشوند نیز وجود دارد و در این مورد خاص بسیار مفید هست، زیرا میتوانیم پیش از رندر کردن Post با استفاده از پارامتر id به دنبال دادههای پست در منابع دادهای خود بگردیم:
1const posts = [
2 { id: 1, title: 'First', content: 'Hello world!' },
3 { id: 2, title: 'Second', content: 'Hello again!' }
4]
5const Post = ({post}) => (
6 <div>
7 <h2>{post.title}</h2>
8 {post.content}
9 </div>
10)
11//...
12<Route exact path="/post/:id" render={({match}) => (
13 <Post post={posts.find(p => p.id === match.params.id)} />
14)} />
Redux
Redux یک ابزار مدیریت حالت است که به طور معمول به همراه React استفاده میشود؛ اما ارتباط مستقیمی با این کتابخانه ندارد و میتواند از سوی فناوریهای دیگر نیز استفاده شود. در هر حال Redux همراه با ریاکت شناخته شده است. Redux روشی برای مدیریت حالت یک اپلیکیشن در اختیار ما قرار میدهد و آن را به یک external global store انتقال میدهد.
چندین مفهوم هستند که باید درک کنید و زمانی که با این مفاهیم آشنا شوید، متوجه میشوید که Redux رویکرد بسیار سادهای برای حل مسئله محسوب میشود.
Redux در اپلیکیشنهای ریاکت کاملاً محبوب است؛ اما به هیچ وجه منحصر به ریاکت نیست و برای همه فریمورکهای محبوب اتصالهایی ارائه شده است. ما در این نوشته مثالهایی را با استفاده از React به عنوان متداولترین کاربرد آن ارائه میکنیم.
چرا باید از Redux استفاده کنیم؟
Redux برای اپلیکیشنهای متوسط رو به بالا بسیار مناسب است. شما صرفاً باید زمانی از آن استفاده کنید که در مدیریت حالت با استفاده از گزارههای پیشفرض حالت در React یا هر کتابخانه دیگری که استفاده میکنید، مشکل داشته باشید. اپلیکیشنهای ساده نباید به هیچ وجه از آن استفاده کنند.
درخت حالت تغییر ناپذیر
در Redux کل حالت اپلیکیشن از سوی یک شیء جاوا اسکریپت به نام State یا State Tree ارائه میشود.
ما آن را «درخت حالت تغییرناپذیر» (Immutable State Tree) مینامیم، زیرا فقط-خواندنی است و نمیتواند مستقیماً تغییر پیدا کند. تنها راه تغییر دادن آن از طریق ارسال یک Action است.
Action-ها
منظور از Action، یک شیء جاوا اسکریپت است که یک تغییر را به روشی کمینه (یعنی صرفاً با اطلاعات ضروری) توصیف میکند:
1{
2 type: 'CLICKED_SIDEBAR'
3}
4// e.g. with more data
5{
6 type: 'SELECTED_USER',
7 userId: 232
8}
تنها الزام برای یک شیء اکشن این است که مشخصه type داشته باشد که مقدار آن یک رشته است.
نوع اکشنها باید ثابت باشد
در یک اپلیکیشن ساده نوع اکشن میتواند به صورت یک رشته تعریف شود و ما نیز چنین کاری را در بخش قبلی انجام دادهایم.
زمانی که اپلیکیشن بزرگتر میشود بهتر است که از ثابتها به این منظور استفاده کنیم:
1const ADD_ITEM = 'ADD_ITEM'
2const action = { type: ADD_ITEM, title: 'Third item' }
و بهتر است که اکشنها را در فایلهای مستقل خود جداسازی و آنها را به صورت زیر ایمپورت کنیم:
1import { ADD_ITEM, REMOVE_ITEM } from './actions'
Action Creator
«ایجادکننده اکشن» (Action Creator) تابعی است که اکشنها را ایجاد میکند.
1function addItem(t) {
2 return {
3 type: ADD_ITEM,
4 title: t
5 }
6}
ما به طور معمول ایجادکننده اکشنها را در ترکیب با راهاندازی یک dispatcher اجرا میکنیم:
1dispatch(addItem('Milk'))
همچنین همراه با تعریف کردن یک تابع dispatcher اکشن نیز اجرا میشوند:
1const dispatchAddItem = i => dispatch(addItem(i))
2dispatchAddItem('Milk')
کاهندهها
زمانی که یک اکشن صادر میشود، اتفاقی باید بیفتد و حالت اپلیکیشن باید تغییر یابد. این کار «کاهندهها» (Reducers) است. یک کاهنده در واقع یک «تابع خالص» (Pure Function) است که حالت بعدی درخت حالت را بر مبنای درخت حالت قبلی و اکشن صادر شده، محاسبه میکند.
1; (currentState, action) => newState
یک تابع خالص یک ورودی میگیرد و یک خروجی را بدون تغییر دادن ویو یا هر چیز دیگری عوض میکند. از این رو یک کاهنده موجب بازگشت یک شیء درخت کاملاً جدید میشود که جایگزین درخت قبلی میشود.
کاهنده چه کارهایی نباید بکند؟
یک کاهنده باید تابعی خالص باشد و از این رو موارد زیر مجاز نیست:
- هرگز نباید آرگومانهایش را تغییر دهد.
- هرگز نباید حالت را تغییر دهد؛ بلکه باید یک حالت جدید با استفاده از ({}, ...)Object.assign ایجاد کند.
- هرگز نباید عارضههای جانبی داشته باشد (هیچ فراخوانی API نباید هیچ چیزی را تغییر دهد).
- هرگز نباید تابعهای غیر خالص یعنی تابعهایی را که خروجی خود را بر مبنای عواملی به جز ورودیشان تغییر میدهند، فراخوانی کند. مثالهایی از تابعهای غیر خالص ()Date.now یا ()Math.random هستند.
البته هیچ الزامی در خصوص موارد فوق وجود ندارد؛ اما شما باید همواره قواعد را رعایت کنید.
کاهندههای چندگانه
از آنجا که حالت یک اپلیکیشن پیچیده میتواند واقعاً پیچیده باشد، در عمل هیچ کاهنده منفردی وجود ندارد؛ بلکه کاهندههای زیادی برای هر نوع اکشن موجود هستند.
شبیهسازی یک کاهنده
Redux در هسته مرکزی خود دارای این مدل ساده است:
حالت
1{
2 list: [
3 { title: "First item" },
4 { title: "Second item" },
5 ],
6 title: 'Groceries list'
7}
لیستی از اکشنها
1{ type: 'ADD_ITEM', title: 'Third item' }
2{ type: 'REMOVE_ITEM', index: 1 }
3{ type: 'CHANGE_LIST_TITLE', title: 'Road trip list' }
یک کاهنده برای هر بخش از حالت
1const title = (state = '', action) => {
2 if (action.type === 'CHANGE_LIST_TITLE') {
3 return action.title
4 } else {
5 return state
6 }
7}
8const list = (state = [], action) => {
9 switch (action.type) {
10 case 'ADD_ITEM':
11 return state.concat([{ title: action.title }])
12 case 'REMOVE_ITEM':
13 return state.map((item, index) =>
14 action.index === index
15 ? { title: item.title }
16 : item
17 default:
18 return state
19 }
20}
یک کاهنده برای کل حالت
1const listManager = (state = {}, action) => {
2 return {
3 title: title(state.title, action),
4 list: list(state.list, action)
5 }
6}
Store
Store یک شیء با خصوصیات زیر است:
- حالت اپلیکیشن را نگهداری میکند.
- حالت را از طریق ()getState افشا میکند.
- امکان بهروزرسانی حالت را از طریق ()dispatch فراهم ساخته است.
- امکان ثبت یک شنونده تغییر حالت را با استفاده از ()subscribe در اختیار ما قرار میدهد.
store برای هر اپلیکیشن منحصر به فرد است.
در ادامه روش ایجاد یک store برای اپلیکیشن listManager را مشاهده میکنید:
1import { createStore } from 'redux'
2import listManager from './reducers'
3let store = createStore(listManager)
آیا میتوانیم Store را با دادههای سرور مقداردهی اولیه بکنیم؟
چنین کاری ممکن است و صرفاً بایستی یک حالت آغازین ارسال شود:
1let store = createStore(listManager, preexistingState)
دریافت کردن حالت
1store.getState()
بهروزرسانی حالت
1store.dispatch(addItem('Something'))
گوش دادن به تغییرات حالت
1const unsubscribe = store.subscribe(() =>
2 const newState = store.getState()
3)
4unsubscribe()
گردش داده
گردش داده در Redux همواره غیر جهتدار است. شما میتوانید ()dispatch را روی store فراخوانی کرده و یک اکشن به آن ارسال کنید. در این حالت store مسئولیت ارسال اکشن به کاهنده و تولید حالت بعدی را بر عهده میگیرد. در ادامه Store حالت خود را بهروزرسانی کرده و به همه شنوندهها هشدار میدهد.
Next.js
کار کردن روی یک اپلیکیشن جاوا اسکریپت مدرن که از React نیرو میگیرد، بسیار جذاب به نظر میرسد؛ تا این که میفهمید چندین مشکل در ارتباط با رندر کردن همه محتوا در سمت کلاینت وجود دارد.
مشکل نخست این است که زمان مورد نیاز برای نمایش صفحه برای کاربر افزایش مییابد؛ چون پیش از آن که محتوا بارگذاری شود، باید همه کدهای جاوا اسکریپت بارگذاری شده باشند و اپلیکیشن نیاز دارد که اجرا شود تا مشخص شود که چیزی باید روی صفحه باید نمایش یابد.
مشکل دوم این است که اگر مشغول ساخت یک وبسایت در دسترس عموم باشید، با مشکلات مرتبط با سئو مواجه میشوید. موتورهای جستجو هم اینک عملکرد خود را در زمینه اجرا و اندیسگذاری اپلیکیشنهای جاوا اسکریپت بهبود بخشیدهاند؛ اما همچنان بسیار بهتر است که به جای این که به آنها اجازه دهیم خودشان محتوای ما را بارگذاری کنند، محتوای آماده خود را به آنها ارسال کنیم.
راهحل هر دو مشکل فوق رندر کردن سمت سرور است که به نام «پیش رندرینگ استاتیک» (Static pre-rendering) نیز نامیده میشود.
Next.js یک فریمورک ریاکت است که با استفاده از آن میتوانید همه این کارها را به روشی بسیار ساده انجام دهید؛ اما محدود به این موارد هم نیست. این فریمورک از سوی خالقانش به نام «مجموعه ابزار تک دستوری با پیکربندی صفر برای اپلیکیشنهای React» نامگذاری شده است.
این فریمورک ساختمان متداولی را ارائه میکند که امکان ساخت آسان اپلیکیشنهای فرانتاند ریاکت را در اختیار شما قرار میدهد و میتوانید به صورت شفافی رندرینگ سمت سروری را مدیریت کنید.
در ادامه فهرست غیر جامعی از ویژگیهای اصلی Next.js را مشاهده میکنید:
- بارگذاری مجدد بیدرنگ کد: Next.js هنگامی که تشخیص دهد هر گونه تغییری روی دیسک ذخیره شده است، صفحه را مجدداً بارگذاری میکند.
- مسیریابی خودکار: هر URL به فایلسیستم و فایلهایی که در پوشه pages قرار دارند نگاشت میشود و دیگر نیاز نیست هیچ گونه پیکربندی انجام دهید. البته امکان سفارشیسازی همچنان وجود دارد.
- کامپوننتهای تک فایلی: با استفاده از styled-jsx که به دلیل ساخته شدن از سوی همان تیم، کاملاً یکپارچهسازی شده است به سادگی میتوانید سبکهایی را در دامنه کامپوننت اضافه کنید.
- رندرینگ سرور: شما میتوانید (در صورت تمایل) کامپوننتهای ریاکت را در سمت سرور و پیش از ارسال TM به کلاینت رندر کنید.
- تطبیق با اکوسیستم: Next.js با بقیه بخشهای اکوسیستم جاوا اسکریپت، Node و React به خوبی کار میکند.
- افراز خودکار کد: صفحهها صرفاً به وسیله کتابخانهها و کد جاوا اسکریپتی که نیاز است رندر میشوند و به چیز دیگری نیاز ندارید.
- «پیشواکشی» (Prefetching): کامپوننت Link برای لینک کردن صفحههای مختلف استفاده میشود و از مشخصه پیشواکشی که به صورت خودکار منابع صفحه را در پسزمینه پیشواکشی میکند نیز پشتیبانی میکند.
- کامپوننتهای دینامیک: شما میتوانید ماژولهای جاوا اسکریپت و کامپوننتهای ریاکت را به صورت دینامیک ایمپورت کنید.
- اکسپورتهای استاتیک: Next.js با استفاده از دستور next export میتواند یک سایت کاملاً استاتیک را از اپلیکیشن شما استخراج و اکسپورت کند.
نصب Next.js
Next.js از همه پلتفرمهای عمده مانند لینوکس، macOS و ویندوز پشتیبانی میکند. یک پروژه Next.js به سادگی با استفاده از npm به صورت زیر آغاز میشود:
npm install next react react-dom
همچنین با استفاده از Yarn به صورت زیر را اندازی میشود:
yarn add next react react-dom
آغاز به کار
یک فایل package.json با محتوای زیر ایجاد کنید:
1{
2 "scripts": {
3 "dev": "next"
4 }
5}
اگر این دستور را اجرا کنید:
npm run dev
اسکریپت مربوطه خطایی در خصوص عدم یافتن پوشه pages صادر میکند. در واقع این تنها نیازمندی Next.js برای شروع به کار است.
یک پوشه خالی pages ایجاد کرده و دستور را مجدداً اجرا کنید تا Next.js به طور خودکار سرور را در مسیر localhost:3000 آغاز کند. اکنون اگر به این URL مراجعه کنید با یک پیام خطای صفحه 404 مواجه میشوید که البته طراحی زیبایی دارد.
Next.js همه انواع خطاها مانند خطاهای 500 را نیز به خوبی مدیریت میکند.
ایجاد یک صفحه
در پوشه pages یک فایل به نام index.js با کامپوننت کارکردی ساده React ایجاد کنید:
1export default () => (
2 <div>
3 <p>Hello World!</p>
4 </div>
5)
اگر از مسیر localhost:3000 بازدید کنید، این کامپوننت به صورت خودکار رندر خواهد شد. شاید از خود بپرسید چرا این قدر ساده است؟ Next.js از یک ساختار اعلانی برای صفحهها استفاده میکند که مبتنی بر ساختار فایلسیستم است.
به بیان ساده صفحههای درون پوشه pages و URL صفحه از روی نام فایل تعیین میشوند. در واقع فایل سیستم همان API صفحهها محسوب میشود.
رندرینگ سمت سرور
در مرورگر کروم با مراجعه به مسیر View -> Developer -> View Source، کد منبع صفحه را باز کنید. همان طور که میبینید HTML ایجاد شده از سوی کامپوننت مستقیماً در منبع صفحه به مرورگر ارسال شده است. این کد در سمت کلاینت رندر نشده است؛ بلکه در سمت سرور رندر شده است.
تیم Next.js میخواستهاند یک تجربه توسعهدهنده برای صفحههای رندر شده در سمت سرور همانند تجربهای که در زمان ایجاد یک پروژه PHP ابتدایی کسب میکنید ارائه دهند. در زبان PHP فایلها را به سادگی در پوشهها قرار میدهیم و آنها را فراخوانی میکنیم و آنها صفحهها را نمایش میدهند. Next.js نیز به روش مشابهی عمل میکند؛ البته تفاوتهای زیادی دارد؛ اما سادگی استفاده از آن کاملاً مشهود است.
افزودن صفحه دوم
در این بخش یک صفحه دیگر در آدرس pages/contact.js ایجاد میکنیم.
1export default () => (
2 <div>
3 <p>
4 <a href="mailto:my@email.com">Contact us!</a>
5 </p>
6 </div>
7)
اگر مرورگر خود را به آدرس localhost:3000/contact هدایت کنید، این صفحه رندر خواهد شد. همان طور که شاهد هستید این صفحه نیز در سمت سرور رندر شده است.
بارگذاری مجدد بیدرنگ
همان طور که در بخش قبل دیدیم برای بارگذاری صفحه دوم نیازی به ریاستارت کردن npm نبود. Next.js این کار را در پسزمینه برای ما انجام میدهد.
رندرینگ کلاینت
رندرینگ سرور در بارگذاری نخست صفحه امری کاملاً رایج است و دلایل آن را قبلاً بررسی کردیم؛ اما زمانی که قرار است درون وبسایت حرکت کنیم، رندرینگ سمت کلاینت موجب افزایش سرعت بارگذاری صفحه و همچنین بهبود تجربه کاربری میشود.
Next.js یک کامپوننت Link ارائه کرده است که میتواند لینکهایی برای شما بسازد. در ادامه تلاش میکنیم دو صفحهای که در بخش قبل ساختیم را به هم لینک کنیم.
به این منظور کد فایل index.js را به صورت زیر تغییر دهید:
1import Link from 'next/link'
2export default () => (
3 <div>
4 <p>Hello World!</p>
5 <Link href="/contact">
6 <a>Contact me!</a>
7 </Link>
8 </div>
9)
اینک به مرورگر بازگردید و این لینک را امتحان کنید. همان طور که میبینید، صفحه جاری بیدرنگ و بدون نیاز به رفرش کردن صفحه، بارگذاری میشود.
این ناوبری سمت کلاینت به دستی کار میکند و پشتیبانی کامی از History API دارد. معنی آن این است که کاربران میتوانند از دکمه back مرورگر نیز استفاده کنند و چیزی از دست نمیرود.
اگر در این زمان روی لینک cmd-click (در ویندوز Ctrl+click) بکنید، همان صفحه Contact در برگه جدیدی باز میشود و این بار روی سرور رندر میشود.
صفحههای دینامیک
یک کاربرد خوب Next.js در زمینه blog است، چون بلاگ چیزی است که همه توسعهدهندهها با طرز کار آن آشنا هستند و برای توضیح روش مدیریت صفحههای دینامیک نیز مناسب است.
یک صفحه دینامیک صفحهای است که هیچ محتوای ثابتی ندارد؛ بلکه به جای آن مقداری دادههای مبتنی بر برخی پارامترها را نمایش میدهد.
فایل index.js را به صورت زیر تغییر دهید:
1import Link from 'next/link'
2const Post = props => (
3 <li>
4 <Link href={`/post?title=${props.title}`}>
5 <a>{props.title}</a>
6 </Link>
7 </li>
8)
9export default () => (
10 <div>
11 <h2>My blog</h2>
12 <ul>
13 <li>
14 <Post title="Yet another post" />
15 <Post title="Second post" />
16 <Post title="Hello, world!" />
17 </li>
18 </ul>
19 </div>
20)
این وضعیت موجب ایجاد یک سری پست میشود و پارامتر کوئری عنوان را با عناوین مطالب پر میکند:
اینک فایل post.js را در پوشه pages ایجاد کرده و کد زیر را اضافه کنید:
1export default props => <h1>{props.url.query.title}</h1>
در ادامه روی یک مطلب منفرد کلیک کنید تا عنوان پست در یک تگ h1 رندر شود:
شما میتوانید از URL-های تمیز بدون پارامترهای کوئری نیز استفاده کنید. کامپوننت Link در Next.js به ما کمک میکند که یک خصوصیت as را بپذیریم و از آن میتوان برای ارسال یک «نشانی مطلب» (Slug) استفاده کرد:
1import Link from 'next/link'
2const Post = props => (
3 <li>
4 <Link as={`/${props.slug}`} href={`/post?title=${props.title}`}>
5 <a>{props.title}</a>
6 </Link>
7 </li>
8)
9export default () => (
10 <div>
11 <h2>My blog</h2>
12 <ul>
13 <li>
14 <Post slug="yet-another-post" title="Yet another post" />
15 <Post slug="second-post" title="Second post" />
16 <Post slug="hello-world" title="Hello, world!" />
17 </li>
18 </ul>
19 </div>
20)
CSS-in-JS
Next.js به صورت پیشفرض از styled-jsx پشتیبانی میکند که یک راهحل CSS-in-JS ارائه شده از سوی همان تیم توسعه است، اما شما میتوانید از هر کتابخانهای که ترجیح میدهید مانند Styled Components استفاده کنید:
مثال:
1export default () => (
2 <div>
3 <p>
4 <a href="mailto:my@email.com">Contact us!</a>
5 </p>
6 <style jsx>{`
7 p {
8 font-family: 'Courier New';
9 }
10 a {
11 text-decoration: none;
12 color: black;
13 }
14 a:hover {
15 opacity: 0.8;
16 }
17 `}</style>
18 </div>
19)
استایل ها در دامنه کامپوننت هستند؛ اما میتوان استایلهای با دامنه سراسری را نیز با افزودن global به عنصر style ویرایش کرد:
1export default () => (
2 <div>
3 <p>
4 <a href="mailto:my@email.com">Contact us!</a>
5 </p>
6 <style jsx global>{`
7 body {
8 font-family: 'Benton Sans', 'Helvetica Neue';
9 margin: 2em;
10 }
11 h2 {
12 font-style: italic;
13 color: #373fff;
14 }
15 `}</style>
16 </div>
17)
اکسپورت کردن سایت استاتیک
یک اپلیکیشن Next.js میتواند به سادگی به صوت یک سایت استاتیک اکسپورت شود. این سایت را میتوان روی یکی از میزبانهای سایت بسیار سریع مانند Netlify یا Firebase Hosting میزبانی کرد و به این ترتیب نیازی هم به راهاندازی محیط Node وجود نخواهد داشت.
این فرایند نیازمند اعلان URL-هایی است که وبسایت را تشکیل میدهند؛ اما در کل فرایند سرراستی محسوب میشود.
توزیع وبسایت
ایجاد یک کپی آماده انتشار از اپلیکیشن بدون نگاشتهای منبع یا دیگر ابزارهای توزیع که در build نهایی مورد نیاز هستند، کار آسانی محسوب میشود.
در ابتدای این راهنما یک فایل package.json با این محتوا ایجاد کردیم:
1{
2 "scripts": {
3 "dev": "next"
4 }
5}
که روشی برای راهاندازی سرور توزیع با استفاده از npm run dev محسوب میشد. اینک محتوای زیر را به جای آن به فایل package.json اضافه میکنیم:
1{
2 "scripts": {
3 "dev": "next",
4 "build": "next build",
5 "start": "next start"
6 }
7}
بدین ترتیب اپلیکیشن خود را با اجرای npm run build و npm run start آمادهسازی میکنیم.
Now
شرکتی که Next.js را خلق کرده است یک سرویس میزبانی جذاب برای اپلیکیشنهای Node.js به نام Now نیز ارائه کرده است. البته آنها هر دو محصول را با هم ترکیب کردهاند به طوری که میتوانید اپلیکیشنهای Next.js را به صورت بیوقفه زمانی که Now را نصب کردید، با اجرای دستور now در پوشه اپلیکیشن توزیع کنید.
Now در پشت صحنه سرور را برای شما راهاندازی میکند و لازم نیست در مورد هیچ چیز دغدغه داشته باشید و کافی است منتظر باشید تا URL اپلیکیشن آماده شود.
Zone-ها
شما میتوانید چندین وهله از Next.js را راهاندازی کنید تا به URL-های متفاوت گوش دهند و با این وجود اپلیکیشن از نظر یک بیگانه این طور به نظر میرسد که گویا از یک سرور منفرد نیرو میگیرد.
افزونهها
Next.js فهرستی از افزونهها دارند که در این آدرس (+) میتوانید آنها را ملاحظه کنید.
Gatsby
Gatsby پلتفرمی برای ساخت اپلیکیشنها و وبسایتها با استفاده از React است. Gatsby یکی از ابزارهایی است که امکان ساخت یک مجموعه از فناوریها و رویهها را فراهم ساخته است که به صورت جمعی به نام JAMstack شناخته میشوند.
اینک Gatsby یکی از ابزارهای جالب در حوزه توسعه فرانتاند محسوب میشود. دلایل آن به شرح زیر هستند:
- استفاده گسترده از رویکرد JAMstack برای ساخت وباپلیکیشنها و وبسایتها.
- استفاده رو به فزونی از فناوری «وباپلیکیشنهای پیشرونده» (+) در این صنعت که یکی از ویژگیهای کلیدی گتسبی محسوب میشود.
- Gatsby در React و GraphQL ساخته شده است که دو فناوری محبوب و رو به رشد هستند.
- Gatsby واقعاً قدرتمند است.
- Gatsby سریع است.
- مستندات Gatsby عالی است.
- Gatsby موفق شده اثر شبکهای ایجاد کند یعنی افراد از آن استفاده میکنند، وبسایت میسازند، افراد بیشتری در مورد آن کسب اطلاع میکنند و یک چرخه ایجاد میشود.
- همه چیز در Gatsby با استفاده از جاوا اسکریپت نوشته شده است و نیازی به یادگیری زبانهای قالببندی جدید وجود ندارد.
- Gatsby پیچیدگی ذاتی خود را در ابتدا پنهان میکند و البته امکان دسترسی به همه مراحل مورد نیاز برای سفارشیسازی را در اختیار شما قرار میدهد.
Gatsby چگونه کار کند؟
اپلیکیشنهای شما با استفاده از Gatsby به وسیله کامپوننتهای React ساخته میشوند. محتوایی که در یک سایت رندر میکنید، عموماً با استفاده از Markdown نوشته میشود؛ اما میتوانید از هر نوع منبع دادهای مانند یک CSS به صورت headless یا وبسرویس همچون Contentful نیز استفاده کنید.
Gatsby سایت را میسازد و به صورت HTML استاتیک کامپایل میشود که میتواند روی هر وبسروری که میخواهید مانند Netlify، AWS S3، GitHub Pages، هر نوع ارائهدهنده خدمات میزبانی وبسایت و یا PAAS توزیع شود. تنها چیزی که نیاز دارید محلی است که صفحههای ساده HTTP و فایلهای شما را به کاربر ارائه کند.
در لیست فوق از وباپلیکیشنهای پیشرونده نیز یاد کردیم. گتسبی به صورت خودکار سایت شما را به صورت یک PWA میسازد. این کار به کمک یک «سرویس ورکر» انجام مییابد که سرعت بارگذاری صفحه و کش شدن منابع را افزایش میدهد.
شما میتوانید کارکردهای گتسبی را از طریق افزونهها ارتقا بدهید.
نصب Gatsby
Gatsby را میتوان با اجرای دستور زیر در ترمینال نصب کرد:
npm install -g gatsby-cli
دستور فوق ابزار CLI مربوط به Gatsby را نصب میکند. زمانی که نسخه جدیدی انتشار یابد، میتوانید با اجرای مجدد دستور فوق آن را بهروزرسانی کنید. با اجرای دستور زیر یک وبسایت «Hello World» جدید ایجاد میشود.
این دستور یک سایت Gatsby کاملاً جدید در پوشه mysite و با استفاده از starter که در این آدرس (+) قرار دارد، ایجاد میکند.
starter یک سایت ساده است که میتوان بر مبنای آن سایتهای دیگری را ساخت. یک استارتر رایج دیگر default است که در این آدرس (+) موجود است.
فهرستی از همه استارتر هایی که میتوان استفاده کرد را میتوانید در این آدرس (+) مشاهده کنید.
اجرای سایت Gatsby
پس از این که ترمینال نصب استارتر را به پایان برد، میتوانید وبسایت را با فراخوانی دستورهای زیر اجرا کنید:
cd mysite gatsby develop
دستورهای فوق یک وبسرور جدید را راهاندازی میکنند و سایت را روی پورت 8000 روی localhost عرضه میکنند.
تصویر وبسایت Hello World در عمل به صورت زیر است:
بررسی سایت
اگر سایتی را که ایجاد کردید با ویرایشگر کد محبوب خود باز کنید، 4 پوشه در آن میبینید:
- پوشه cache.: این یک پوشه پنهان است که شامل موارد داخلی Gatsby است و چیزی که لازم باشد در حال حاضر تغییر دهید در آن وجود ندارد.
- پوشه public: این پوشه پس از ساخت وبسایت، شامل آن خواهد بود.
- پوشه src: این پوشه شامل کامپوننتهای react است که در این مورد کامپوننت index را شامل میشود.
- پوشه static: این پوشه شامل منابع استاتیک مانند CSS و تصاویر است.
اینک ایجاد یک تغییر ساده در صفحه پیشفرض کار سادهای محسوب میشود. کافی است فایل src/pages/index.js را باز کنید و «Hello world!» را به چیز دیگری تغییر دهید و آن را ذخیره کنید. در این حالت، مرورگر باید بیدرنگ کامپوننت را بارگذاری مجدد بکند. این بدان معنی است که صفحه رفرش نمیشود؛ اما محتوای آن تغییر مییابد. این ترفند از سوی فناوریهای تشکیلدهنده آن ممکن شده است.
برای افزودن یک صفحه دوم کافی است یک فایل js. دیگر در همان پوشه ایجاد کنید و همان محتوای index.js را در آن قرار داده و ذخیره کنید. در ادامه محتوای آن را دستکاری خواهیم کرد.
برای نمونه یک فایل second.js را با محتوای زیر ایجاد میکنیم:
1import React from 'react'
2export default () => <div>Second page!</div>
و مرورگر را باز کرده و به آدرس زیر میرویم:
http://localhost:8000/second
لینک کردن صفحهها
میتوان این صفحهها را با استفاده از ایمپورت کردن یک کامپوننت React به نام Link به هم لینک کرد:
1import { Link } from "gatsby"
همچنین میتوان آن را در JSX کامپوننت مورد استفاده قرار داد:
1<Link to="/second/">Second</Link>
افزودن CSS
میتوان هر فایل CSS را با استفاده از ایمپورت جاوا اسکریپت، ایمپورت کرد:
1import './index.css'
میتوانید از استایلدهی React نیز استفاده کنید:
1<p style={{
2 margin: '0 auto',
3 padding: '20px'
4 }}>Hello world</p>
استفاده از افزونهها
Gatsby چیزهای زیادی را به صورت آماده عرضه میکند؛ اما بسیاری از کارکردهای آن در افزونهها نهفته هستند. گتسبی سه نوع افزونه دارد:
افزونههای سورس
این افزونهها به واکشی دادهها از یک منبع میپردازند. گرههایی را ایجاد میکنند که میتوان در ادامه با استفاده از افزونههای transformer آنها را فیلتر کرد.
افزونههای transformer
این افزونهها دادههای ارائه شده از سوی افزونههای سورس را به چیزی تبدیل میکنند که گتسبی بتواند استفاده کند.
افزونههای کاربردی
این افزونهها به پیادهسازی برخی از انواع کارکردها مانند افزودن پشتیبانی از «نقشه سایت» (sitemap) و موارد دیگر میپردازند.
برخی از افزونههای پرکاربرد گتسبی به شرح زیر هستند:
- gatsby-plugin-react-helmet
این افزونه (+) امکان ویرایش محتوای تگ head را فراهم میسازد.
- gatsby-plugin-catch-links
این افزونه (+)-ای است که از History API استفاده میکند تا جلوی بارگذاری مجدد صفحه در زمان کلیک شدن یک لینک را بگیرد و به جای آن محتوای جدید را با استفاده از AJAX بارگذاری کند.
یک افزونه گتسبی در 2 مرحله نصب میشود. ابتدا آن را با استفاده از npm نصب میکنیم و سپس آن را در فایل gatsby-config.js به پیکربندی گتسبی اضافه میکنیم. برای نمونه میتوانید افزونه Catch Links را با دستور زیر نصب کنید:
npm install gatsby-plugin-catch-links
در فایل gatsby-config.js (اگر این فایل را ندارید در پوشه ریشه وبسایت آن را بسازید) افزونه را به آرایه اکسپورت شده plugins اضافه کنید:
1module.exports = {
2 plugins: ['gatsby-plugin-catch-links']
3}
کار به همین سادگی است، اینک افزونه کار خود را انجام خواهد داد.
ساخت وبسایت استاتیک
زمانی که کار دستکاری سایت پایان یافت و خواستید یک سایت استاتیک نهایی بسازید میتوانید دستور زیر را اجرا کنید:
gatsby build
در این زمان میتوانید با آغاز کردن یک وبسرور محلی با استفاده از دستور زیر، بررسی کنید که آیا همه چیز مطابق انتظار کار میکند یا نه:
gatsby serve
دستور فوق سایت را تا حد امکان شبیه به آنچه در توزیع نهایی خواهید دید، رندر میکند.
توزیع
زمانی که سایت را با استفاده از gatsby build ساختید، تنها کاری که باید انجام دهید توزیع نتیجه سایت حاصل، در پوشه public است.
بسته به این که از چه راهحلی استفاده میکنید به این منظور باید مراحل مختلفی را طی کنید؛ اما به طور کلی لازم است که سایت را به یک ریپازیتوری Git ارسال کنید و اجازه بدهید قلابهای پس از کامیت Git کار توزیع را بر عهده بگیرند. در این آدرس (gatsby serve) میتوانید در این خصوص راهنماییهای بیشتری برای پلتفرمهای محبوب دریافت کنید.
جمعبندی
بدین ترتیب به پایان این سری مقالات آموزش جامع ریاکت میرسیم. امیدواریم این مطالب جامع برای شما مفید بوده باشد و دستکم نقطه شروعی برای بررسی جنبههای پیشرفتهتر برنامهنویسی React در اختیار شما قرار داده باشد.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- راهنمای جامع React (بخش اول) — از صفر تا صد
- مجموعه آموزشهای جاوا اسکریپت
- مجموعه آموزشهای طراحی و توسعه پروژه های وب
- رندر کادرهای Modal در React — به زبان ساده
- آموزش React.js در کمتر از ۵ دقیقه — از صفر تا صد
==
سلام و وقت بخیر
برای این که بتوانیم راهنمایی بکنیم، لطفاً مشکلتان را دقیقتر توضیح دهید، چه کاری میخواهید انجام دهید و کدام روش پاسخگو نبوده است و با چه خطایی مواجه شدهاید.
با تشکر
با سلام
من برای قرار دادن عکس در reactjs مشکل دارم میشه راهنماییم کنید حتی این رووش هم جواب نداده