در این مقاله­ آموزش React Native، نوشتنِ برنامه­‌های نیتیو را با استفاده از کتابخانه­‌ی بسیار معروفِ جاوااسکریپتِ React یاد خواهید گرفت. تمرکز اصلی ما روی پلتفرم اندروید است.

تفاوت اصلی React Native با سایر فریم ورک‌ها:

تفاوت اصلی React Native با سایر فریمورک­‌ها، مانندِ (PhoneGap)(Apache cordova) یا تیتانیوم شرکت (Appcelerator Titanium) که از جاوااسکریپت برای توسعه­ برنامه‌­های iOSای استفاده می­کنند، چیست؟

  1. (برخلافِ فون­گپ) با استفاده از React Native کد شما به زبانِ جاوااسکریپت نوشته می‌­شود، اما UI برنامه کاملاً نیتیو است. این برنامه مشکلاتی را، که برنامه‌­های هیبریدی HTML5 اغلب با آن مواجه­‌اند، ندارد.
  2. به‌­علاوه (برخلافِ تیتانیوم)، ری­اکت رویکردی تازه، اساسی و بسیار کارامد را برای ساخت واسط­‌های کاربری معرفی می­کند. UI­تان متدی از حالت کنونی برنامه (current app state) است.

آموزش PhoneGap و Cordova (ششمین دوره از مجموعه صد روز تا دولوپری)

React Native ،ری ­‌اکت را وارد حوزه­ برنامه‌­های موبایلی می‌­کند. هدفش این نیست که یکبار برنامه‌­ای را بنویسیم و بعد بتوانیم آن را روی هر پلتفرمی اجرا کنیم. هدف یادگیری یکباره (به شیوه­ی ری­اکت) و کدنویسی در هرجایی است. تصمیمی مهم که باید گرفته شود.

انجمن حتی ابزارهایی مانندِ  Expo و Create React Native App را برای کمک بهتان اضافه کرده است تا بدون نیاز به Xcode یا اندروید استودیو بتوانید برنامه­‌های React Native را بنویسید.

می­‌توانید برنامه­‌های React Native را هم برای اندروید و هم برای iOS بنویسید، اما در این آموزش تنها به اندروید می­پردازیم.

در این مقاله­ آموزشی مراحلِ نوشتن یک برنامه­ اندرویدی را برای جست­­وجوی املاک در بریتانیا خواهید دید.

نگران این موضوع نباشید که هرگز قبلاً کدِ جاوا اسکریپت ننوشته­اید یا از ویژگی­هایی مانند CSS که در ادامه می­بینید، استفاده نکرده‌­اید. در این آموزش گام به گام پیش خواهیم رفت و برای یادگیری بیشتر شما منابعی را معرفی خواهیم کرد.

آماده­اید؟ به خواندن ادامه دهید.

شروع به کار

Node و JDK

React Native از Node.js، که یک محیط اجرایی جاوااسکریپت است، برای ساختِ کد جاوااسکریپت شما استفاده می­‌کند. React Native هم­چنین از یک نسخه­‌ی به­‌روزِ JDK برای اجرای برنامه­‌ی اندروید استفاده می­‌کند. دستورالعمل­‌های زیر را برای سیستم خودتان اجرا کنید تا از نصبِ ورژن­‌های لازم مطمئن شویم.

آموزش Node.js رایگان – راهنمای جامع مبتدیان پروژه محور

سیستم عامل مک (MacOs)

در ابتدا با استفاده از راهنمایی‌­های موجود در سایت Homebrew ، Homebrew را نصب کنید. سپس با اجرای کد زیر در ترمینال Node.js را نصب کنید.

brew install node

سپس، از homebrew  برای نصبِ Watchman استفاده کنید. واچ­من یک فایل­واچر (File Watcher) از شرکت فیسبوک است.

brew install watchman

ری­اکت نیتیو از واچ­من استفاده می­کند تا تغییراتِ انجام شده روی کد را بفهمد و مطابق با آن برنامه را ری­بیلد (rebuild) کند. این کار دقیقاً شبیه اندروید استودیو است که در هر بار ذخیره­ فایل برنامه را بیلد (build) می­کند.

در پایان نیز اگر لازم بود، JDK8 یا ورژن جدیدتر آن را دانلود و نصب کنید.

سیستم عامل ویندوز (Windows)

در ابتدا با استفاده از راهنمایی­‌های موجود در سایت Chocolatey، Chocolatey را نصب کنید.

اگر Node.js ندارید یا نسخه­ آن قدیمی‌­تر از ۴ است، آن را نصب کنید. کد زیر را در حالت Administrator اجرا کنید. (روی برنامه­ command prompt راست کلیک کنید و “Run as Administrator” را انتخاب کنید.)

choco install -y nodejs.install

برای اجرای بیلد اسکریپت­های (Build Scripts) ری­اکت نیتیو، پایتون لازم داریم. اگر پایتون۲ را نصب ندارید، کد زیر را در حالت Administrator اجرا کنید:

اگر JDK را نصب ندارید یا نسخه­ی آن قدیمی­تر از ۸ است، کد زیر را در حالت Administrator اجرا کنید:

choco install -y python2

لینوکس (Linux)

با استفاده از “دستورالعمل­های نصبِ موجود برای توزیع لینوکس”  Node.js را نصب کنید. به ورژن ۶ یا جدیدتر از آن نیاز خواهید داشت.

در آخر و در صورت نیاز، JDK 8 یا ورژن جدیدتر آن را دانلود و نصب کنید.

React Native CLI

از Node Package Manager (یا nmp) برای نصبِ واسط دستوری ری­اکت نیتیو (CLI) استفاده کنید. در ترمینال (ترمینال، command prompt یا shell) تایپ کنید:

npm install -g react-native-cli

دستور npm به طور کلی ابزار CLI را دانلود و نصب می­‌کند. عملکرد nmp مشابه JCenter (لینک موجود در مقاله­ی اصلی اضافه گردد) است و در پکیج Node.js قرار گرفته است.

در ادامه، با استفاده از راهنمایی‌­های موجود در سایت Yarn ، Yarn را نصب کنید. یارن کلاینتی پرسرعت برای nmp است.

محیط توسعه­ اندروید (Android development Environment)

اگر قبلا محیط توسعه­ اندروید خود را برپا نکرده­اید، این کار را انجام دهید. مطمئن شوید که یک برنامه­ اندرویدی به خوبی در امولاتور (emulator) اجرا می‌­شود.

React Native به Android 6.0 (Marshmallow) نیاز دارد. در اندروید استودیو مسیر روبه­‌رو را دنبال کنید: Tools/Android/SDK Manager. SDK Platforms و سپس Show Package Details را انتخاب کنید. مطمئن شوید که همه­ آیتم‌­های زیر انتخاب شده­‌اند:

  • Google APIs, Android 23
  • Android SDK Platform 23
  • Intel x86 Atom_64 system Image
  • Google APIs Intel x86 Atom_64 System Image

آموزش React Native

در ادامه SDK Tools و سپس Show Package Details را انتخاب کنید. با کلیک روی فلش،Android SDK Build Tools را باز کنید و بررسی کنید که ۲۳.۰.۱ انتخاب شده باشد.

در آخر برای نصب آنها روی Apply کلیک کنید.

پس از اینکه اندروید کامپوننت­‌های انتخابی را نصب کرد، با اجرای SDK Platform 23 امولاتوری بسازید.

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

به پوشه‌­ای بروید که می­خواهید برنامه را در آن ذخیره کنید و کد زیر را در ترمینال اجرا کنید:

react-native init PropertyFinder

این کد از CLI استفاده می­کند و پروژه­ای اولیه را برایتان می­‌سازد که شامل همه­ چیزهایی است که برای ساخت و اجرای برنامه­ React Native به آن نیاز دارید.

در ترمینال کد زیر را اجرا کنید:

cd PropertyFinder

در پوشه‌­ها و فایل­‌های ایجاد شده برخی آیتم‌­های قابل توجه را پیدا خواهید کرد:

  • node_modules پوشه­ای است که فریمورک React Native در آن هستند.
  • js نقطه­ اجرای برنامه (Entry point) است که CLI آن را ساخته است.
  • js برنامه­ اصلی است که CLI آن را ایجاد کرده است.
  • android پوشه‌­ای است که پروژه­ اندروید و کدی که برای bootstrap کردن برنامه به آن احتیاج دارید، در آن هستند.
  • iOS پوشه­‌ای است که کدهای مربوط به iOS در آن است و در این آموزش به آن کاری نخواهید داشت.

اگر امولاتور اندروید در حال اجرا نیست، آن را با اجرای SKD 23 اجرا کنید.

کد زیر را در ترمینال اجرا کنید:

react-native run-android

امولاتور تصویر زیر را نشان خواهد داد.

آموزش React Native

اگر پیغام خطایی به صورت “SDK location not found!” دریافت کردید، کارهای زیر را به ترتیب انجام دهید:

  • به پوشه­ android/ پروژه­ی react-native خود بروید.
  • با استفاده از کد زیر، فایلی با نام local.properties ایجاد کنید.
sdk.dir = {PATH TO ANDROID SDK}

برای مثال، در سیستم عامل مک، مسیر SDK چیزی شبیه این است:

پیشنهاد فرانش به شما
آموزش انگولار جی‌ اس از صفر تا صد (به همراه راهنمای نصب)

/Users/USERNAME/Library/Android/sdk.

حتماٌ متوجه شدید که پنجره­ ترمینالی باز شده است و چیزی شبیه تصویر زیر را نشان می­دهد:

آموزش React Native

این Metro Bundler است، یک باندلر جاوااسکریپت برای React Native که در Node.js اجرا می­شود. کمی بعد به­‌خوبی درباره­ وظیفه­ آن توضیح خواهم داد.

پنجره­ ترمینال را نبندید و بگذارید در پس­ زمینه اجرا شود. اگر اشتباهاً آن را بستید، تنها کافی است کد زیر را در ترمینال اجرا کنید:

react-native start

توجه: در این آموزش React Native، کد جاوااسکریپت می­نویسید و نیازی به اندروید استودیو برای ویرایش کدهای خود ندارید. من از Sublime Text استفاده می­کنم که برنامه­‌ای ارزان و همه­‌کاره است، اما می­‌توانید از برنامه­‌هایی مثل Atom ، Brackets یا هر برنامه­ ویرایش متن سبک دیگری برای کد نویسی استفاده کنید.

موضوعات پایه­ React Native

در این بخش، با کار کردن روی PropertyFinder با موضوعات پایه­ React Native آشنا خواهید شد.

را با برنامه­ ویرایش فایل انتخابی خود، فایل App.js باز کنید و نگاهی به ساختار کد بیندازید:

import React, { Component } from 'react'; // 1
import {Platform, StyleSheet, Text, View} from 'react-native';

const instructions = Platform.select({ ... }); // 2

type Props = {};
export default class App extends Component<Props> { ... } // 3

const styles = StyleSheet.create({ ... }); // 4

بیایید با هم گام به گام کد را بررسی کنیم:

  1. ماژول­‌های لازم را ایمپورت (import) می­‌کند.
  2. یک پیغام متناسب با پلتفرم را تنظیم می­‌کند.
  3. کامپوننتی (component) را، که مسئول UI است، تعریف می­کند.
  4. شئ­ای با نام styles ایجاد می­کند که layout و ظاهر کامپوننت را کنترل می­کند.

نگاهی دقیق­‌تر به این کد ایمپورت بیندازید:

import React, { Component } from 'react';

این کد از سینتکس ایمپورت ECMAScript 6 ES6 برای لود کردن ماژول react و اختصاص آن به متغیری به نام React استفاده می­‌کند. این کار تقریبا مشابه ایمپورت کردن کتابخانه­‌ها در اندروید است. هم­چنین از چیزی به نام destructuring assignment برای آوردن شئ Component به برنامه استفاده می­‌کند. Destructuring به شما این امکان را می­دهد که چندین property شئ را برداشته و با استفاده از تنها یک خط کد آنها را به چندین متغیر اختصاص دهید.

استفاده از ES6 روشی بهتر برای نوشتن جاوااسکریپت است، چون از ویژگی­‌هایی مانند پارامترهای دیفالت، کلاس­‌ها، توابع فلش (استفاده از علائم برای کوتاه کردن سینتکس توابع) (arrow functions) و Destructuring assignment پشتیبانی می­کند. تمامی مرورگرها از ES6 پشتیبانی نمی­‌کنند. ری­اکت نیتیو از ابزاری به نام Babel استفاده می­کند تا در صورت لزوم به صورت خودکار کد جاوااسکریپت مدرن را به کد جاوااسکریپت قدیمیِ سازگار با مرورگر ترجمه کند.

برگردیم سراغ App.js، به تعریف کلاس نگاهی بیندازید:

export default class App extends Component<Props>

این کد، کلاسی را تعریف می­‌کند که از یک Component ری­اکت ارثبری (Extend) دارد. Modifier کلاس export default کلاس را پابلیک (Public) می‌کند و اجازه­ استفاده از این کلاس را در سایر فایل­‌ها می‌دهد.

فایل index.js را باز کنید و نگاهی به فایل نقطه­ی شروع اجرای برنامه (entry point) بیندازید:

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);

این کد کامپوننت ایمپورت شده را به عنوان نقطه­ شروع اجرای برنامه تعیین می­‌کند.

حالا زمانِ نوشتن برنامه­ رسیده است.

در فایل App.js، کد زیر را در بالای برنامه و قبل از کدهای مربوط به ایمپورت وارد کنید:

'use strict';

این کد حالت Strict Mode, را فعال می­کند. در این حالت راحت­‌تر می‌­شود خطاها را مدیریت کرد و برخی از ویژگی­‌های نامناسب زبان جاوااسکریپت غیرفعال می­‌شوند. به زبانی ساده، این کد جاوااسکریپت را بهتر می­کند!

در کلاس App، به جای render() کد زیر را قرار دهید:

render() {
  return React.createElement(Text, {style: styles.description}, "Search for houses to buy!");
}

کلاس App از React.Component ارث می­برد، که ابتدایی­ترین قسمت UI ری­اکت است. کامپوننت­‌ها شامل immutable properties (خصیصه­‌های تغییرناپذیر) و Mutable state variables (متغیرهای استیت تغییرپذیر) هستند و تابعی را برای رندر گرفتن عرضه می­‌کنند. برنامه­ موردنظر بسیار ساده است و تنها به یک متد رندر نیاز دارد.

کامپوننت­‌های React Native شبیه کلاس­‌های view اندروید نیستند، بلکه معادل سب‌ک­تر آنها هستند. فریمورک، درخت کامپوننت­‌های ری­اکت را به UI نیتیو موردنیاز تبدیل می­کند.

درادامه، به جای const styles کد زیر را بنویسید:

const styles = StyleSheet.create({
  description: {
    fontSize: 18,
    textAlign: 'center',
    color: '#656565',
    marginTop: 65,
  },
});

این کد استایلی ساده به متنِ توضیحات شما می‌­دهد. اگر قبلاٌ کد نویسی تحت وب کار کرده باشید، احتمالاٌ برخی از اسامی propertyهای بالا برایتان آشناست. کلاسِ StyleSheet ری­اکت نیتیوی که برای تنظیم استایلِ UI برنامه استفاده شده، مشابه با Cascading Style Sheets CSS است که در برنامه‌­نویسی تحت وب از آن استفاده می­‌شود.

سپس تکه کد instructions را حذف کنید چون دیگر به آن نیازی ندارید.

تغییرات را در App.js ذخیره کنید و امولاتور را باز کنید. دو بار دکمه­ R کیبورد را بزنید و می­بینید که برنامه­ جست­وجوی ملک نوپای شما کم­کم روی صفحه شکل می­گیرد:

آموزش React Native

چیزی که می­بینید، یک برنامه­ جاوااسکریپت است که در امولاتور اجرا می­‌شود و بدون داشتن مرورگری، آن را به یک UI نیتیو ترجمه می­کند! (عمل رندر گرفتن)

هنوز باور نمی­‌کنید؟ خودتان بررسی کنید. در برنامه­ اندروید استودیو، مسیر روبه‌­رو را دنبال کنید: Tools\Android\Layout Inspector. سپس Show All Processes و com.propertyfinder را انتخاب کرده و روی okay کلیک کنید تا سلسله مراتب را بررسی کنید.

آموزش React Native

اثری از WebView نمی­بینید! متن شما در viewای به نام ReactTextView نشان داده می­شود.

آموزش React Native

اما ReactTextView دقیقاً چیست؟ به project file finder بروید و در بخش prompt عبارت ReactTextView.java را وارد کنید. نتایج مشابه با این نام را انتخاب کنید تا سورس­‌کد آن را ببینید. دقت کنید که ReactTextView مستقیماً از TextView ارث می­برد. عالی است!

می خواهید بدانید که دقیقاً چطور کار می­کند؟ نگاهی گذرا به MainActivity.java و MainApplication.java بیندازید. می­‌توانید آنها را در مسیر زیر پیدا کنید:
android/app/src/main/java/com/propertyfinder.

MainApplication یک ReactNativeHost را برپا می­کند و ReactNativeHost نیز در عوض یک ReactInstanceManager می­سازد. این instant manager ارتباطات بین جاوااسکریپت و اندروید نیتیو را مدیریت می­‌کند.

MainActivity از ReactActivity ارث می­برد که با شروع اجرا یک ReactRootView می­سازد. ReactRootView با استفاده از instant manager برنامه جاوااسکریپت را اجرا می‌­کند. هم­چنین از کامپوننت Appرندر می­گیرد تا به Content View اکتیویتی (Activity) مقدار دهد.

پنجره­ ترمینالی که هنگام اجرای این برنامه باز بود، یک پکجر (packager) و سرور روی پورت دیفالتِ ۸۰۸۱ باز می­‌کند که به کد جاوااسکریپت شما امکان فِچ شدن (Fetch) می­‌دهد.

http://localhost:8081/index.bundle?platform=android

URL بالا را در مرورگر خود باز کنید و آن وقت کد جاوااسکریپت مربوط به برنامه­ خود را می­بینید. می­‌توانید کد توضیح “Search for houses to buy!” را میانِ فریمورک React Native  ببینید.

وقتی برنامه­ شما اجرا می­‌شود، این کد به وسیله­ کتابخانه­ JavaScriptCore خوانده و اجرا می­‌شود، در برنامه­ شما، کامپوننت App را می­خواند و سپس view Native اندروید را می­سازد.

استفاده از JSX

برنامه­ حال حاضر شما از React.createElement برای ساخت UI ساده­ی برنامه­‌تان استفاده می­‌کند و ری­اکت آن را به معادل نیتیو اندرویدی تبدیل می­کند. اگرچه کد جاوااسکریپت در حالت کنونی­اش بسیار خوانا است، اما UIای پیچیده‌­تر با المنت­‌هایی تودرتو سریعاً کدی آشفته تولید می­کند.

وقتی مطمئن شدید که برنامه هنوز درحال اجراست، به برنامه­ ویرایشگر متن خود بروید تا App.js را تغییر دهید. محتوای داخل render را به شکل زیر تغییر دهید:

return <Text style={styles.description}>Search for houses to buy! (Again)</Text>;

این کد JSX است یا JavaScript syntax extension، که سینتکس­‌های مشابه HTML را مستقیماً به کد جاوااسکریپت شما اضافه می­‌کند. اگر توسعه­‌دهنده­ وب باشید، این موضوع برایتان آشناست. در این آموزش از JSX استفاده خواهید کرد.

پیشنهاد فرانش به شما
15 فناوری که شیوهٔ کار برنامه‌نویس‌ها رو تغییر می‌ده

تغییرات را در App.js ذخیره کنید و به سراغ امولاتور بروید. دو بار دکمه­ R را بزنید و می­بینید که برنامه‌­تان رفرش (Refresh) می­شود تا پیغام جدید را نمایش دهد:

آموزش React Native

اجرای مجدد یک برنامه­ React Native به سادگی رفرش کردن یک مرورگر وب است! توجه داشته باشید که این موضوع تنها برای تغییراتی درست است که در فایل جاوااسکریپت انجام می­دهید. تغییر کد نیتیو یا ریسورس­ها نیازمند راه اندازی مجدد پکجر (Packager) است.

با فعال کردن live reload حتی دیگر نیازی به رفرش کردن برنامه ندارید. در سیستم عامل مک Cmd+m و در ویندوز یا لینوکس Ctrl/m را در امولاتور بزنید و گزینه­ی Enable Live Reload را انتخاب کنید.

آموزش React Native

در فایل App.js، محتوای متد render را به شکل زیر تغییر دهید:

return <Text style={styles.description}>Search for houses to buy!</Text>;

تغییرات را ذخیره کنید. توجه کنید که امولاتور به صورت خودکار برای نشان دادن تغییرات شما رفرش می­شود:

آموزش React Native

افزودن Navigation

React Navigation حاصل تلاش­‌های انجمنی است که فیسبوک و Expo مدیریت آن را به­‌عهده داشتند تا راهکاری ساده برای navigation در برنامه‌های React Native ارائه دهند. این Navigation بر پایه­ جاوااسکریپت پیاده­‌سازی شده است بنابراین در هر دو پلتفرم اندروید و iOS کار می­کند. از این کتابخانه در این آموزش استفاده خواهید کرد.

راهکارهای نیتیو دیگری برای Navigation وجود دارند، مانند  Native Navigation ارائه شده توسط شرکت AirBnB و React Native Navigation شرکت Wix. اگر به دنبال ظاهری نیتیوتر برای برنامه­ آتی خود هستید، حتماً گزینه­‌های جایگزین دیگر را نیز بررسی کنید.

با اجرای کد زیر در ترمینال، Navigation ری­اکت را نصب کنید:

yarn add react-navigation

حالا می‌­توانید از کامپوننت­های Navigation آن استفاده کنید.

در App.js کد زیر را در بالای صفحه و بعد از کدهای ایمپورت وارد کنید:

import {
  createStackNavigator,
} from 'react-navigation';

createStackNavigator به برنامه­ شما این امکان را می­دهد که در آن از یک صفحه به صفحه­ دیگر بروید و صفحه­ جدید در بالای استک (پشته) قرار بگیرد.

در ادامه، کد زیر را به جای تعریف کلاس App قرار دهید:

class SearchPage extends Component<Props> {

سپس کد زیر را بهSearchPage  و بعد از render() اضافه کنید:

static navigationOptions = {
  title: 'Property Finder',
};

این کد عنوان Navigation Bar را برای این صفحه تنظیم می­کند.

کد زیر را بعد از کامپوننت SearchPage وارد کنید:

const App = createStackNavigator({
  Home: { screen: SearchPage },
});
export default App;

این کد کامپوننت SearchPage را به عنوان کامپوننت آغازین در استکِ Navigation درنظر می­گیرد.

تغییرات را ذخیره کنید و برای دیدنِ UI جدید به سراغ امولاتور بروید:

آموزش React Native

بسیار عالی. حالا ساختار اولیه navigation را دردسترس دارید.

ساختن صفحه­ جست­جو

فایلی جدید با نام SearchPage.js بسازید و آن را در پوشه­ App.js قرار دهید. کد زیر را به فایل اضافه کنید:

'use strict';

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  TextInput,
  View,
  Button,
  ActivityIndicator,
  Image,
} from 'react-native';

این کد ماژول­‌هایی را که برای ساخت UI لازم دارید، ایمپورت می­کند.

ساب­کلاس Component زیر را بعد از کدهای ایمپورت قرار دهید:

type Props = {};
export default class SearchPage extends Component<Props> {
  static navigationOptions = {
    title: 'Property Finder',
  };

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.description}>
          Search for houses to buy!
        </Text>
        <Text style={styles.description}>
          Search by place-name or postcode.
        </Text>
      </View>
    );
  }
}

render مثالی عالی از JSX و ساختاری است که ارائه می­دهد. در کنار تنظیم استایل، به راحتی می­توانید UIای که با این کامپوننت ساخته­اید را نمایش دهید. Containerای با دو لیبل متنی.

حالا، کد استایل زیر را به انتهای فایل اضافه کنید:

const styles = StyleSheet.create({
  description: {
    marginBottom: 20,
    fontSize: 18,
    textAlign: 'center',
    color: '#656565'
  },
  container: {
    padding: 30,
    marginTop: 65,
    alignItems: 'center'
  },
});

این­‌ها Propertyهای استاندارد CSS هستند. تنظیم استایل به این صورت، کم­تر از layout design editor اندروید استودیو از ابزارهای نمایشی استفاده می­کند، اما بسیار بهتر از این است که propertyهای مربوط به view را تک­تک در متدهای onCreate() مقداردهی کنید!

تغییرات را ذخیره کنید.

App.js را باز کنید و کد زیر را بعد از آخرین کد import و نزدیک بالای صفحه وارد کنید:

import SearchPage from './SearchPage';

این کد SearchPage را از فایلی که کمی قبل­تر ساختید، ایمپورت می­کند.

کلاس SearchPage و استایل مربوط به آن یعنی description را از App.js پاک کنید. دیگر احتیاجی به این کد ندارید. حالا وقت آن رسیده که از شر تمامی ایمپورت­های استفاده نشده نیز خلاص شوید: تمامی کدهای ایمپورت مربوط به react و react-native.

تغییرات را ذخیره کنید و برای بررسی UI جدید به سراغ امیلاتور بروید:

آموزش React Native

افزودن استایل با استفاده از Flexbox

تا اینجا، با propertyهای ابتدایی CSS که با margin، Padding و رنگ کار می­کردند، آشنا شدید. اگرچه ممکن است با Flexbox آشنا نباشید؛ ویژگی جدیدی که به CSS اضافه شده است که برای مدیریت layoutهای پیچیده در صفحه­ نمایش‌­هایی با اندازه­های مختلف مناسب است.

React Native در پس‌­زمینه از کتابخانه­ Yoga برای مدیریت layout استفاده می­کند. Yoga پیاده‌­سازی Flexbox به زبان سی است و bindingهای زبان‌های جاوا (برای اندروید)، سوئیفت، آبجکتیو سی (Objective-C) و C# (برای .NET) را داراست.

به طور کلی از propertyهای flexDirection، alignItems و justifyContent Yoga برای مدیریت layout خود استفاده می­کنید.

تا اینجا، layout شما دارای یک container است که دو فرزند خود را به صورت عمودی تنظیم کرده است.

آموزش React Native

این به خاطر فعال بودن مقدار دیفالت flexDirection برای column است. flexDirection به تنظیم main axis و cross axis کمک می­کند. مقدار main axis کانتینر vertical است. بنابراین مقدار cross axis آن horizontal است.

alignItems به تعیین موقعیت فرزندان در cross axis کمک می­کند. برنامه­ی شما مقدار آن را center قرار داده است. این یعنی فرزندارن center-aligned شده­اند.

در ادامه گزینه­‌های layout دیگری را خواهید دید.

فایل SearchPage.js را باز کنید و کد زیر را بعد از } دومین المنت Text وارد کنید:

<View style={styles.flowRight}>
  <TextInput
    underlineColorAndroid={'transparent'}
    style={styles.searchInput}
    placeholder='Search via name or postcode'/>
  <Button
    onPress={() => {}}
    color='#48BBEC'
    title='Go'
  />
</View>

شما یک view اضافه کردید که دارای یک text input و یک button است.

در تعریف­های استایل برنامه، تنظیمات استایل جدید زیر را بعد از container استایل وارد کنید:

flowRight: {
  flexDirection: 'row',
  alignItems: 'center',
  alignSelf: 'stretch',
},
searchInput: {
  height: 36,
  padding: 4,
  marginRight: 5,
  flexGrow: 1,
  fontSize: 18,
  borderWidth: 1,
  borderColor: '#48BBEC',
  borderRadius: 8,
  color: '#48BBEC',
},

این کد موقعیت input text و button را مشخص می­‌کند.

تغییرات را ذخیره کنید و برای دیدن آنها به سراغ امولاتور بروید:

آموزش React Native

text field و دکمه­ GO در یک ردیف هستند. با استفاده از flowRight آنها را در یک کانتینر قرار داده­اید. flowRight از flexDirection: ‘row’ برای قرار دادن آیتم­ها در یک ردیف استفاده می­کند.

flexGrow: 1 را به input text اضافه کردید. Yoga ابتدا text input و button را مطابق با اندازه­‌هایشان قرار می­دهد. سپس فضای باقی­مانده را براساس مقادیر flexGrow پخش می­‌کند. بنابراین text input فضای باقی مانده را پُر می­کند.

مدیریت Assetها

گام نهایی برای کامل کردن صفحه­ی جست­وجوی برنامه، اضافه کردن تصاویر خانه­‌هاست. images zip file را دانلود و از حالت زیپ خارج کنید.

پیشنهاد فرانش به شما
آموزش رایگان انگولار 8 Angular پروژه محور

در ادامه، پوشه­‌ای به نام Resources در پوشه­ی پروژه‌­تان ایجاد کنید. سه عکس خانه را در این پوشه قرار دهید.

drawables: در اندروید، تصاویر برنامه­ ایستا معمولاٌ به پوشه­ res/drawable برنامه افزوده می­شوند. اگرچه در React Native به این کار recommended not to . نگهداری تصاویر در کنار کامپوننت­‌ها به آنها کمک می­کند تا خود را مدیریت کنند. در این حالت دیگر لازم نیست که برنامه، در صورت افزودن تصاویر جدید، راه­اندازی مجدد شود. هم­چنین اگر برنامه را هم برای اندروید و هم برای iOS می­نویسید، تنها یک پوشه برای ذخیره­ تصاویر در اختیارتان قرار می­دهد.

برگردیم سراغ SearchPage.js. کد زیر را بعد از } کامپوننت Viewای وارد کنید که شامل text input و button است:

<Image source={require('./Resources/house.png')} style={styles.image}/>

حالا استایل مربوط به تصاویر را به انتهای لیست استایل خود وارد کنید:

image: {
  width: 217,
  height: 138,
},

تغییرات را ذخیره کنید و نگاهی به UI جدید خود بیندازید:

آموزش React Native

اگر تصاویر نمایش داده نشدند، باید packager را در ویندوز ری­استارت کنید.

برنامه­ حال حاضر خوب به‌­نظر می­رسد، اما عملکردی ندارد. وظیفه­ بعدی­‌تان این است که چند state به آن اضافه کنید و کارهایی انجام دهید.

افزودن State به کامپوننت

یک کامپوننت ری­اکت می­تواند state داخلی­اش را با صدا زدن شئ­‌ای به نام، بله درست حدس زدید، state مدیریت کند. با هربار تغییر state کامپوننت، render() فراخوانی می­شود.

در فایل SearchPage.js، کد زیر را قبل از render() وارد کنید:

constructor(props) {
  super(props);
  this.state = {
    searchString: 'london'
  };
}

searchString دارای مقدار اولیه­ london است و کامپوننت شما یک متغیر state دارد.

در داخل render()، TextInput را به صورت زیر تغییر دهید:

<TextInput
  underlineColorAndroid={'transparent'}
  style={styles.searchInput}
  value={this.state.searchString}
  placeholder='Search via name or postcode'/>

این کد مقدار کنونی متغیر استیت searchString را در TextInput قرار می­دهد. این همان متنی است که برای کاربر نمایش داده می­شود. این کد مقداردهی اولیه­ استیت را انجام می­دهد، اما اگر کاربر متن را ویرایش کند، چه اتفاقی می­افتد؟

گام اول ساخت متدی است که به عنوان یک event handler عمل می­کند. کد زیر را در کلاس SearchPage و بعد از constructor وارد کنید:

_onSearchTextChanged = (event) => {
  console.log('_onSearchTextChanged');
  this.setState({ searchString: event.nativeEvent.text });
  console.log('Current: '+this.state.searchString+', Next: '+event.nativeEvent.text);
};

این کد با استفاده از سینتکس => یک تابع تعریف می­‌کند. این یک تابع فلش (Arrow Function) است که اخیراً به زبان جاوااسکریپت اضافه شده استو سینتکسی کوتاه برای ساخت توابع بی­‌نام ارائه می‌­کند.

این تابع مقدارِ text را در event مرورگر نیتیو می­گیرد و از آن برای به‌­روزرسانی state کامپوننت استفاده می­کند. هم­چنین کدهای logging را نیز اضافه می­کند که کمی بعد درباره­ آنها توضیح خواهم داد.

توجه: کلاس­های جاوااسکریپت access modifier ندارند و بنابراین private در آنها مفهومی ندارد. درنتیجه معمولاً می­بینید که برنامه­نویسان از متدهایی با نام­های پیشوندی، که با یک _ شروع می­شوند، استفاده می­کنند تا نشان دهند که آن کلاس باید private درنظر گرفته شود.

برای ساخت این متد و برای اینکه با هر تغییر متن فراخوانی شود، به سراغ فیلد TextInput در متد render بروید و onChange را به آن اضافه کنید تا به شکل زیر دربیاید:

<TextInput
  underlineColorAndroid={'transparent'}
  style={styles.searchInput}
  value={this.state.searchString}
  onChange={this._onSearchTextChanged}
  placeholder='Search via name or postcode'/>

با هربار تغییر متن توسط کاربر، متدی که به onChange داده شده است را فراخوانی می­کنید، در این کد، این متد _onSearchTextChanged است.

قبل از رفرش مجدد برنامه، یک کار دیگر نیز باید انجام دهید. درست قبل از return و در بالای render()، کد logging زیر را وارد کنید:

console.log('SearchPage.render');

تغییرات را ذخیره کنید و دوباره به سراغ امولاتور بروید. باید در برنامه‌­تان مقدار اولیه­ text input عبارت London باشد.

آموزش React Native

برای مشاهده­ لاگ­های دیباگ عبارت زیر را در ترمینال وارد کنید:

react-native log-android

در امولاتور، متن input text را تغییر دهید. متنی مشابه زیر خواهید دید:

۰۸-۰۱ ۱۸:۰۹:۰۲.۷۲۰  ۵۴۴۴  ۸۰۲۸ I ReactNativeJS: SearchPage.render
۰۸-۰۱ ۱۸:۰۹:۳۳.۴۵۳  ۵۴۴۴  ۸۰۲۸ I ReactNativeJS: _onSearchTextChanged
۰۸-۰۱ ۱۸:۰۹:۳۳.۴۵۳  ۵۴۴۴  ۸۰۲۸ I ReactNativeJS: Current: london, Next: londona
۰۸-۰۱ ۱۸:۰۹:۳۳.۴۵۴  ۵۴۴۴  ۸۰۲۸ I ReactNativeJS: SearchPage.render

اگر به لاگ­‌های کنسول دقت کنید، ترتیب loggingها کمی عجیب به نظر می­رسد.

  1. این فراخوانی اولیه­ی render() برای ایجاد view است.
  2. با تغییر متن _onSearchTextChanged() را صدا می­کنید.
  3. this.setState() را صدا می­کنید تا state کامپوننت را برای نشان دادن input text جدید آپدیت کند. این کار موجب render() دیگری می­شود.
  4. متن­های جست­وجوی جدید و قبلی را لاگ می­کنید.

تغییر state یک کامپوننت ری­اکت موجب به‌­روزرسانی UI می­­‌شود. این مسئله منطق rendering را از تغییرات stateای که موجب به روزرسانی UI می­شوند، جدا می­کند. بیشتر فریمورک­های UI دیگر  این را به­عهده­ی خودتان می­گذارند که براساس تغییرات state، UI را به­روزرسانی کنید. از طرفی، به­روزرسانی­ از طریق لینکی ضمنی بین state و UI انجام می­گیرد. برای مثال با استفاده از کتابخانه­ Data Binding  اندروید.

تا اینجا حتما متوجه عیبی اساسی در این موضوع شده­‌اید. بله، درست است، سرعت!

مطمئناً با هربار تغییر نمی­توانید کل UI قبلی را دور بریزید و همه­چیز را از اول بسازید. این همان­جایی است که ری­اکت بسیار هوشمند می­شود.

هر بار که UI از خود render می­گیرد، درخت view را از طریق متدهای render پس می­گیرد و آن را با UI کنونی view اندروید یکی می­کند (یا با هم مقایسه می­کند تا بفهمد چقدر با هم فرق دارند). حاصل این مقایسه لیستی ساده از آپدیت­هاست که ری­اکت باید روی view کنونی اعمال کند. یعنی تنها از چیزهایی که واقعاً تغییر کرده­اند render گرفته می­شود.

بعداً می­توانید به همه­ی این چیزها فکر کنید و آنها را متوجه شوید، فعلاً باید کارهای بیشتری را در برنامه انجام دهید.

راه­‌اندازی جست­وجو

ابتدا کد loggingای که کمی قبل­تر اضافه کردید را پاک کنید، دیگر به آن نیازی ندارید.

برای پیاده­‌سازی عملکرد جست­وجو باید انتخاب دکمه­ Go را مدیریت کنید، درخواست API مناسبی بسازید و در صفحه به کاربر نشان دهید که جست­وجویی درحال انجام است.

در فایل SearchPage.js، مقدار اولیه­ state را در سازنده (constructor) به صورت زیر تغییر دهید:

this.state = {
  searchString: 'london',
  isLoading: false,
};

isLoading بررسی می­کند که آیا جست­وجو در حال انجام است یا نه.

کد زیر را به اول render اضافه کنید:

const spinner = this.state.isLoading ?
  <ActivityIndicator size='large'/> : null;

if موجود در کد یک if سه­‌تایی است که به صورت اختیاری و براساس استیت isLoading کامپوننت، یک activity indicator اضافه می­کند. چون در هربار از کل کامپوننت render گرفته می­شود، می­توانید منطق JSX و جاوااسکریپت را با هم تلفیق کنید.

برای قرار دادن spinner، کد زیر را که UI جست­وجو را در قسمت return می­سازد، در JSX اضافه کنید.

{spinner}

در ادامه، متدهای زیر را به کلاس SearchPage اضافه کنید:

_executeQuery = (query) => {
  console.log(query);
  this.setState({ isLoading: true });
};

_onSearchPressed = () => {
  const query = urlForQueryAndPage('place_name', this.state.searchString, 1);
  this._executeQuery(query);
};

_executeQuery() در انتها کوئری موردنظر را جست­وجو می­کند، اما درحال حاضر تنها پیغامی را به کنسول می­فرستد و isLoading را به­گونه­ای مناسب تنظیم می­کند تا UI بتواند state جدید را نمایش دهد.

_onSearchPressed() عبارت جست­وجو را کانفیگر و مقداردهی می­کند. با زدن Go، این کار انجام می­شود.

برای انجام این کار، به متد render بروید و onPress را برای Go Button به صورت زیر قرار دهید:

onPress={this._onSearchPressed}

در آخر، تابع utility زیر را قبل از تعریف کلاس SearchPage اضافه کنید:

function urlForQueryAndPage(key, value, pageNumber) {
  const data = {
      country: 'uk',
      pretty: '1',
      encoding: 'json',
      listing_type: 'buy',
      action: 'search_listings',
      page: pageNumber,
  };
  data[key] = value;

  const querystring = Object.keys(data)
    .map(key => key + '=' + encodeURIComponent(data[key]))
    .join('&');

  return 'https://api.nestoria.co.uk/api?' + querystring;
}

urlForQueryAndPage به SearchPage وابسته نیست، به همین دلیل به جای متد بودن، به صورت تابعی مستقل پیاده­سازی شده است. ابتدا متن جست­وجو را بر اساس پارامترهای درون data می­سازد. سپس data را به صورت جفت­های name=value درمی­آورد که با & از هم جدا می­شوند. در آخر، Nestoria APIرا صدا می­زند تا لیست املاک را برگرداند.

پیشنهاد فرانش به شما
آموزش ری اکت رایگان : یادگیری React 2019

تغییرات خود را ذخیره کنید و دوباره به سراغ امولاتور بروید و Go را بزنید. می­بینید که activity indicator می­چرخد:

آموزش React Native

لاگ‌­های دیباگ ترمینال باید چیزی شبیه زیر باشد:

۰۸-۰۱ ۱۸:۱۴:۴۵.۱۱۰  ۵۴۴۴  ۸۳۰۸ I ReactNativeJS: https://api.nestoria.co.uk/api?country=uk&pretty=1&encoding=json&listing_type=buy&action=search_listings&page=1&place_name=london

URL بالا را کپی و در مرورگر خود پیست کنید، تا نتایج را ببینید. یک شئ JSON بزرگ خواهید دید. نگران نباشید، لازم نیست آن را بفهمید! کدهای لازم برای پارس آن را بعداً اضافه خواهید کرد.

اجرای یک درخواست API

در فایل SearchPage.js مقدار اولیه­ی state را در سازنده­ی کلاس (constructor) به صورت زیر تغییر دهید تا یک متغیر message را به انتهای لیست اضافه کنید:

message: '',

در render، درست بعد از spinner، کد زیر را انتهای UI خود وارد کنید:

<Text style={styles.description}>{this.state.message}</Text>

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

کد زیر را به آخر _executeQuery اضافه کنید:

fetch(query)
  .then(response => response.json())
  .then(json => this._handleResponse(json.response))
  .catch(error =>
     this.setState({
      isLoading: false,
      message: 'Something bad happened ' + error
   }));

این کد از تابع fetch استفاده می­کند، که بخشی از Fetch API است. پاسخ آسنکرون به صورت یک Promise بازگردانده می­شود. درخواست دارای پاسخ Success Path، _handleResponse را صدا می­زند تا پاسخ JSON را پارس کند. این را در ادامه تعریف خواهید کرد.

تابع زیر را به SearchPage اضافه کنید:

_handleResponse = (response) => {
  this.setState({ isLoading: false , message: '' });
  if (response.application_response_code.substr(0, 1) === '1') {
    console.log('Properties found: ' + response.listings.length);
  } else {
    this.setState({ message: 'Location not recognized; please try again.'});
  }
};

این کد isLoading را آزاد می­کند و در صورت موفقیت­‌آمیز بودن پرس‌­وجو، تعداد املاک پیدا شده را لاگ می­کند.

تغییرات خود را ذخیره کنید و دوباره به سراغ امولاتور بروید و Go را بزنید. باید پیغامِ دیباگی را ببینید که می­گوید ۲۰ ملک (اندازه­ی دیفالت تعداد نتایج) پیدا شده­ است.

هم­چنین توجه کنید که با لاگ شدن این پیغام، spinner ناپدید می­شود.

حالا زمان آن رسیده که ببینیم این ۲۰ ملک چگونه هستند!

۰۸-۰۱ ۱۸:۱۸:۰۷.۲۶۱  ۵۴۴۴  ۸۴۴۷ I ReactNativeJS: Properties found: 20

نمایش نتایج

یک فایل جدید به نام SearchResults.js بسازید و کد زیر را به آن اضافه کنید:

'use strict';

import React, { Component } from 'react'
import {
  StyleSheet,
  Image,
  View,
  TouchableHighlight,
  FlatList,
  Text,
} from 'react-native';

این کد ماژول­‌هایی که در ادامه خواهید دید، ایمپورت می­کند.

در ادامه، کامپوننت را اضافه کنید:

type Props = {};
export default class SearchResults extends Component<Props> {
  static navigationOptions = {
    title: 'Results',
  };

  _keyExtractor = (item, index) => index.toString();

  _renderItem = ({item}) => {
    return (
      <TouchableHighlight
        underlayColor='#dddddd'>
        <View>
          <Text>{item.title}</Text>
        </View>
      </TouchableHighlight>
    );
    
  };

  render() {
    const { params } = this.props.navigation.state;
    return (
      <FlatList
        data={params.listings}
        keyExtractor={this._keyExtractor}
        renderItem={this._renderItem}
      />
    );
  }
}

کد بالا از کامپوننتی تخصصی‌­تر به نام FlatList استفاده می­کند. این کامپوننت سطرها را درون یکscrolling container نمایش می­دهد و شبیه RecyclerView است. نگاهی به propertyهای FlatList بیندازید:

  • data داده­ای را که می­خواهیم نمایش دهیم، ارائه می­دهد.
  • keyExtractor یک کلید منحصربه­فرد را ارائه می­دهد که ری­اکت از آن برای مدیریت مناسب لیست استفاده می­کند.
  • renderItem مشخص می­کند که برای هر سطر چگونه از UI رندر گرفته شود.

فایل جدید را ذخیره کنید.

کد زیر را در App.js و درست بعد از کدهای import وارد کنید:

import SearchResults from './SearchResults';

این کد، کلاس جدید SearchResults را صدا می­زند.

حالا، createStackNavigator را به صورت زیر عوض کنید:

const App = createStackNavigator({
  Home: { screen: SearchPage },
  Results: { screen: SearchResults },
});

این کد مسیری جدید را به navigator می­دهد و SearchResults را به عنوان کامپوننتِ مدیرِ این مسیر درنظر می­گیرد. زمانی که یک کامپوننت به navigator رجیستر می­شود، یک پراپرتی navigation به آن افزوده می­شود. از این property برای انتقال صفحات و داده‌­ها استفاده می­شود.

تغییرات را ذخیره کنید.

در فایل SearchPage.js به سراغ _handleResponse بروید و کد زیر را به جای console.log قرار دهید:

this.props.navigation.navigate(
  'Results', {listings: response.listings});

این کد به مسیر جدیدی که اضافه کردید می­رود و لیست داده­هایی را که از درخواست API گرفته است، از طریق آرگومان params انتقال می­دهد.

تغییرات را ذخیره کنید و به سراغ امولاتور بروید و Go را بزنید. با لیستی از املاک مواجه خواهید شد:

آموزش React Native

عالی است که می­توانیم لیست املاک را ببینیم، اما این لیست کمی بی­روح است. زمان آن رسیده که کمی به آن رنگ و روح بدهیم.

استفاده از کمی استایل

تعریف استایل زیر را به آخر SearchResults.js اضافه کنید:

const styles = StyleSheet.create({
  thumb: {
    width: 80,
    height: 80,
    marginRight: 10
  },
  textContainer: {
    flex: 1
  },
  separator: {
    height: 1,
    backgroundColor: '#dddddd'
  },
  price: {
    fontSize: 25,
    fontWeight: 'bold',
    color: '#48BBEC'
  },
  title: {
    fontSize: 20,
    color: '#656565'
  },
  rowContainer: {
    flexDirection: 'row',
    padding: 10
  },
});

این کد تمامی استایل مورد استفاده برای رندر گیری از هر سطر را تعریف می­کند.

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

class ListItem extends React.PureComponent {
  _onPress = () => {
    this.props.onPressItem(this.props.index);
  }

  render() {
    const item = this.props.item;
    const price = item.price_formatted.split(' ')[0];
    return (
      <TouchableHighlight
        onPress={this._onPress}
        underlayColor='#dddddd'>
        <View>
          <View style={styles.rowContainer}>
            <Image style={styles.thumb} source={{ uri: item.img_url }} />
            <View style={styles.textContainer}>
              <Text style={styles.price}>{price}</Text>
              <Text style={styles.title}
                numberOfLines={1}>{item.title}</Text>
            </View>
          </View>
          <View style={styles.separator}/>
        </View>
      </TouchableHighlight>
    );
  }
}

این کد فرمت قیمت را، که به صورت ۳۰۰,۰۰۰ GBP است، عوض و پسوند GBP را خذف می­کند. سپس با استفاده از تکنیک­هایی که تا کنون با آنها آشنا شدید، از هر سطر UI رندر می­گیرد. توجه داشته باشید که یک Image به هر سطر اضافه می­شود که از یک پاسخ URL (item.img_url) برداشته می­شود. ری­اکت نیتیو آن را خارج از نخ اصلی برنامه دی­کد می­کند.

ممکن است متوجه شده باشید که این کامپوننت از React.PureComponent ارث­بری دارد. ری­اکت در صورتی که property یا state یک Component تغییر کند، دوباره از آن رندر می­گیرد. ری­اکت تنها زمانی از یک PureComponent رندر می­گیرد که حاصل shallow compare تغییراتی را در state یا property نشان دهد. اگر در شرایط مناسب از این ویژگی استفاده کنید، این کار می­تواند سرعت برنامه­ی شما را بالا ببرد.

حالا کد زیر را به جای _renderItem قرار دهید:

_renderItem = ({item, index}) => (
  <ListItem
    item={item}
    index={index}
    onPressItem={this._onPressItem}
  />
);

_onPressItem = (index) => {
  console.log("Pressed row: "+index);
};

_onPressItem به ListItem داده می­شود تا انتخاب یک سطر را مدیریت کند. این نوع طراحی، مشابه Callback است. در این Callback، ایندکس سطر انتخاب شده لاگ می­شود.

تغییرات را ذخیره کنید، دوباره به سراغ امولاتور بروید، Go را بزنید و نتایج خود را ببینید:

آموزش React Native

با انگشت روی اولین سطر بزنید و بررسی کنید که کنسول دیباگ­تان به انتخاب واکنش نشان می­دهد:

۰۸-۰۱ ۱۸:۳۲:۰۰.۶۷۰  ۵۴۴۴  ۹۰۴۷ I ReactNativeJS: Pressed row: 0

انتخاب سطرهای دیگر یا مکان­های دیگر در بریتانیا را برای جست­وجو امتحان کنید.

 

در صورتی‌که این راهنمای مقدماتی برای شما مفید بود:

برای یادگیری کامل تر میتوانید مقدمه‌ای بر ReactJS و Redux را مشاهده نمایید.