شرکت پلاتین با مقاله ای دیگر در خدمت شما می باشد.
در این مقاله ، شرکت پلاتین ، به بررسی کتابخانه react navigation خواهیم پرداخت.
در این مقاله به معرفی روش ساخت اپلیکیشنهای ریاکت با استفاده از نسخه کتابخانه React Native Navigation میپردازیم. نسخه دوم کتابخانه React Native Navigation اخیراً انتشار یافته است. به همین دلیل ، در این نوشته تلاش کردهایم به معرفی و بررسی آن بپردازیم. این کتابخانه یک پیادهسازی از ناوبری نیتیو و نه یک پیادهسازی مبتنی بر جاوا اسکریپت می باشد. این بدان معنی می باشد که این کتابخانه به طور معمول عملکرد بالاتری داشته و از تعاملها و گذار صفحه روانتری در مقایسه با دیگر راهحلهایی که پیادهسازی نیتیو ندارند برخوردار است.
نسخه ۲ کتابخانه React Native Navigation یک بازنویسی از نسخه اول این کتابخانه می باشد که برخی از مشکلات آن را که در نسخه اول پیدا شدند رفع کرده است. در این راهنما روش ساخت یک گردش کار احراز هویت واقعی را میسازیم که یک شبیهسازی از حالت احراز هویت با استفاده از AsyncStorage است. البته میتوانید از هر ارائهدهنده سرویس احراز هویت که خودتان انتخاب میکنید استفاده کنید.
گردش کار چگونه می باشد؟
هنگامی که اپلیکیشن لود میشود، یک کامپوننت مقداردهی (Initializing) ابتدایی را بارگذاری میکنیم. در همان هین بررسی می شود که آیا کاربری در حافظه دستگاه ذخیره شده است یا خیر. اگر کاربری در حافظه دستگاه وجود داشته باشد، مسیر Home را در یک ناوبری مبتنی بر stack رندر میکنیم.
اگر کاربری در حافظه دستگاه موجود نباشد، کامپوننتهای auth (یعنی SignIn و SignUp) را در یک ناوبری مبتنی بر tab پیگیری میکنیم.
آغاز کار
در ابتدای کار ، باید یک پروژه ریاکت نیتیو را با استفاده از React Native CLI بسازیم:
react-native init RNNav2
سپس از npm یا yarn برای نصب ناوبری ریاکت نیتیو استفاده می کنیم:
npm install react-native-navigation@alpha # or yarn add react-native-navigation@alpha
اینک باید وابستگیهای نیتیو را لینک کرده و مقداری کد نیتیو نیز بنویسیم.
ایجاد فایلها
در این مرحله ، فایلهایی که برای این اپلیکیشن نیاز هستند را ایجاد میکنیم. ابتدا یک پوشه به نام src در دایرکتوری root ایجاد میکنیم تا همه چیز را در آن بنویسیم:
mkdir src
سپس فایلهای زیر را در دایرکتوری src میسازیم:
cd src touch config.js Home.js Initializing.js SignIn.js SignUp.js screens.js navigation.js Screen2.js
حال کارکرد این فایلها را توضیح می دهیم:
فایل config.js: این فایل برخی اطلاعات پیکربندی مقدماتی اپلیکیشن را در خود جای می دهد که در مورد مثال بالا شامل کلید AsyncStorage برای بازیابی کاربر از حافظه است.
فایل Home.js: این فایل در صورت وارد شدن کاربر به حساب، شامل کامپوننت خواهد بود.
فایل Initializing.js: این فایل منطق مقداردهی اولیه را در خود جای داده و در زمان بارگذاری اپلیکیشن یک پیام به عنوان خروجی برای کاربر نشان میدهد.
فایل Signin.js / SignUp.js: این فایلها شامل فرمهای ثبت نام و ورود کاربر هستند. در فایل Signin.js یک بازهدایت کاربر به صفحه Home نیز تعبیه شده است.
فایل screens.js: این فایل پیکربندی صفحه را برای کتابخانه React Native Navigation در خود جای داده است.
فایل navigation.js: این فایل تابعهای ناوبری را در خود جای میدهد. ما دو تابع اصلی به نامهای ()goToAuth و ()goHome داریم.
فایل Screen۲.js: این فایل شامل کامپوننت دیگری برای ناوبری به/از صفحه اصلی اپلیکیشن است که از ناوبری پشتهای stack بهره میگیرد.
ثبت کردن صفحهها
در زمان استفاده از React Native Navigation باید هر یک از صفحهها را که در اپلیکیشن ما استفاده خواهد شد ثبت کرد.
به این منظور از متد registerComponent در کتابخانه React Native Navigation استفاده میشود. همه صفحههایی را که میخواهیم مقداردهی کنیم، در یک تابع منفرد قرار میدهیم و آن را پیش از ایجاد root ناوبری خود فراخوانی میکنیم.
// screens.js import {Navigation} from 'react-native-navigation'; export function registerScreens() { Navigation.registerComponent('Home', () => require('./Home').default); Navigation.registerComponent('Initializing', (sc) => require('./Initializing').default); Navigation.registerComponent('SignIn', () => require('./SignIn').default); Navigation.registerComponent('SignUp', () => require('./SignUp').default); Navigation.registerComponent('Screen2', () => require('./Screen2').default); }
در این کد ، یک تابع را ایجاد و اکسپورت کردهایم که ()Navigation.registerComponent را روی هر کامپوننتی که میخواهیم در ناوبری خود داشته باشیم، فراخوانی میکند.
ثبت کردن اپلیکیشن
سپس فایل index.js را طوری بهروزرسانی میکنیم که پشته ناوبری ابتدایی اپلیکیشن تنظیم و مقداردهی شود.
// index.js import {Navigation} from 'react-native-navigation'; import {registerScreens} from './src/screens'; registerScreens(); Navigation.events().registerAppLaunchedListener(() => { Navigation.setRoot({ root: { component: { name: 'Initializing' } }, }); });
در کد فوق تابع registerScreens را ایمپورت و فراخوانی میکنیم.
همچنین ریشه ابتدایی پشته اپلیکیشن را با فراخوانی Navigation.setRoot تعیین کرده و مسیرهای اولیه را که میخواهیم اپلیکیشن ما رندر کند به آن ارسال میکنیم. در این مورد root یک کامپوننت منفرد، به نام صفحه Initializing خواهد بود.
ایجاد تابعهای ناوبری
اکنون، نوبت به ایجاد چند تابع با قابلیت استفاده مجدد رسیده است که میتوان از آن برای تعیین ریشه پشتههای مسیر درون اپلیکیشن بهره گرفت.
مسیر ریشه یا root همان جایی می باشد که پشته مسیر اصلی را در آن تعریف میکنیم. ما میخواهیم گزینه ریست کردن پشتهی ریشه را به مسیرهای احراز هویت و یا در صورت وارد شدن کاربر، به خود اپلیکیشن واقعی در اختیار داشته باشیم:
// navigation.js import { Navigation } from 'react-native-navigation' export const goToAuth = () => Navigation.setRoot({ root: { bottomTabs: { id: 'BottomTabsId', children: [ { component: { name: 'SignIn', options: { bottomTab: { fontSize: 12, text: 'Sign In', icon: require('./signin.png') } } }, }, { component: { name: 'SignUp', options: { bottomTab: { text: 'Sign Up', fontSize: 12, icon: require('./signup.png') } } }, }, ], } } }); export const goHome = () => Navigation.setRoot({ root: { stack: { id: 'App', children: [ { component: { name: 'Home', } } ], } } })
تصاویری که برای برگههای فوق استفاده میکنیم، به صورت زیر هستند. شما میتوانید آنها را ذخیره کرده و مورد استفاده قرار دهید.
تصویر برگه ورود (SignIn):
تصویر برگه ثبت نام (SignUp):
در فایل navigation.js دو تابع موجود می باشد:
- goToAuth – این تابع پشته مسیر ریشه ما را به پیکربندی مسیر bottomTabs تنظیم میکند. هر برگه یک کامپوننت می باشد که نام و برخی گزینهها برای آن پیکربندی شده است.
- goHome – این تابع پشته مسیر را به صورت ناوبری stack تعیین میکند و یک کامپوننت منفرد را به آرایه فرزندان یعنی کامپوننت Home ارسال میکند.
ذخیرهسازی کلید AsyncStorage در یک فایل پیکربندی
ما به بررسی AsyncStorage میپردازیم تا ببینیم آیا کاربر قبلاً ثبت نام کرده است یا خیر. این کار در چند فایل صورت میگیرد. کلید AsyncStorage را در یک فایل جداگانه ذخیره میکنیم تا بتوانیم آن را به سادگی مورد استفاده مجدد قرار دهیم.
// config.js export const USER_KEY = 'USER_KEY'
ایجاد صفحات
اکنون همه پیکربندیهای ناوبری را که لازم بوده را ایجاد کردهایم و نوبت به آن رسیده است که صفحهها و کامپوننتهایی که مورد استفاده قرار خواهیم داد را بسازیم.
فایل Initializing.js
// Initializing.js import React from 'react' import { View, Text, StyleSheet, AsyncStorage } from 'react-native' import { goToAuth, goHome } from './navigation' import { USER_KEY } from './config' export default class Initialising extends React.Component { async componentDidMount() { try { const user = await AsyncStorage.getItem(USER_KEY) console.log('user: ', user) if (user) { goHome() } else { goToAuth() } } catch (err) { console.log('error: ', err) goToAuth() } } render() { return ( <View style={styles.container}> <Text style={styles.welcome}>Loading</Text> </View> ) } } const styles = StyleSheet.create({ welcome: { fontSize: 28 }, container: { flex: 1, justifyContent: 'center', alignItems: 'center' } })
اگر به کلاس componentDidMount نگاه کنید میبینید که اغلب کارهای عمده در این فایل صورت میگیرند. ما AsyncStorage را بررسی میکنیم تا ببینیم آیا کاربری در حافظه دستگاه ذخیره شده است یا نه و در صورتی که چنین حالتی وجود داشته باشد صفحه Home را بارگذاری میکنیم و در غیر این صورت مسیرهای Auth یعنی SignIn و SignUp را بارگذاری خواهیم کرد.
زمانی که کلاس componentDidMount منطق مورد نیاز برای بررسی ذخیره شدن کاربر در دستگاه را اجرا میکند؛ یک پیام بارگذاری را برای کاربری نمایش میدهیم. سپس پشته مسیر را بر مبنای این که کاربر موجود است یا نه ریست میکنیم.
فایل Home.js
// Home.js import React from 'react' import { View, Text, Button, StyleSheet, AsyncStorage } from 'react-native' import { goToAuth } from './navigation' import {Navigation} from 'react-native-navigation'; import { USER_KEY } from './config' export default class Home extends React.Component { static get options() { return { topBar: { title: { text: 'Home' }, } }; } logout = async () => { try { await AsyncStorage.removeItem(USER_KEY) goToAuth() } catch (err) { console.log('error signing out...: ', err) } } render() { return ( <View style={styles.container}> <Text>Hello from Home screen.</Text> <Button onPress={this.logout} title="Sign Out" /> <Button onPress={() => { Navigation.push(this.props.componentId, { component: { name: 'Screen2', } }); }} title="View next screen" /> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' } })
در این فایل یک پیام ابتدایی را برای کاربر رندر میکنیم و این گزینه را در اختیار وی قرار میدهیم که یا از برنامه خارج شود و یا به مسیر دیگری برود.
یک نکته متفاوت که باید در این بخش مورد اشاره قرار داد، روش فراخوانی متدهای ناوبری است. ما به جای استفاده از props مانند نسخه قدیمی (this.props.navigator.push) یعنی API مربوط به Navigation را ایمپورت کرده و Navigation.push را فراخوانی میکنیم.
همچنین متوجه یک تابع کلاس استاتیک به نام ()get options میشویم. این تابع را میتوان به تعریف کامپوننت ریاکت صفحه اضافه کرد و سبکبندی و مشخصهها را به ظاهر ناوبری افزود. در مورد مثال مورد بررسی، ما صرفاً یک مشخصه عنوان برای topBar استفاده کردهایم.
فایل Screen۲.js
import React from 'react' import { View, Text, Button, StyleSheet, } from 'react-native' import {Navigation} from 'react-native-navigation'; export default class Screen2 extends React.Component { static get options() { return { topBar: { title: { text: 'Screen 2' }, } }; } render() { return ( <View style={styles.container}> <Text>Screen 2</Text> <Button onPress={() => Navigation.pop(this.props.componentId)} title="Go Back" /> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' } })
این فایل یک صفحه کاملاً ابتدایی می باشد که صرفاً برای نمایش ناوبری در یک ناوبری پشتهای از صفحه Home مورد استفاده قرار می گیرد. نکتهای که باید اشاره کرد، شیوه فراخوانی تابع Navigation.pop می باشد. این روش نیز از نسخه قدیمی API که در آن از props استفاده میشد (this.props.navigator.pop) متفاوت می باشد و در نسخه ۲ از API Navigation ایمپورت شده از کتابخانه React Native Navigation با نام استفاده میکنیم.
فایل SignUp.js
// SignUp.js import React from 'react' import { View, Button, TextInput, StyleSheet } from 'react-native' export default class SignUp extends React.Component { state = { username: '', password: '', email: '', phone_number: '' } onChangeText = (key, val) => { this.setState({ [key]: val }) } signUp = async () => { const { username, password, email, phone_number } = this.state try { // here place your signup logic console.log('user successfully signed up!: ', success) } catch (err) { console.log('error signing up: ', err) } } render() { return ( <View style={styles.container}> <TextInput style={styles.input} placeholder='Username' autoCapitalize="none" placeholderTextColor='white' onChangeText={val => this.onChangeText('username', val)} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} autoCapitalize="none" placeholderTextColor='white' onChangeText={val => this.onChangeText('password', val)} /> <TextInput style={styles.input} placeholder='Email' autoCapitalize="none" placeholderTextColor='white' onChangeText={val => this.onChangeText('email', val)} /> <TextInput style={styles.input} placeholder='Phone Number' autoCapitalize="none" placeholderTextColor='white' onChangeText={val => this.onChangeText('phone_number', val)} /> <Button title='Sign Up' onPress={this.signUp} /> </View> ) } } const styles = StyleSheet.create({ input: { width: 350, height: 55, backgroundColor: '#42A5F5', margin: 10, padding: 8, color: 'white', borderRadius: 14, fontSize: 18, fontWeight: '500', }, container: { flex: 1, justifyContent: 'center', alignItems: 'center' } })
فایل SignUp.js در حال حاضر صرفاً یک محفظه خالی برای فرم ثبت نام محسوب میشود. میتوان از این محفظه برای پیادهسازی سرویس احراز هویت مورد استفاده بهره گرفت.
فایل SignIn.js
// SignIn.js import React from 'react' import { View, Text, StyleSheet, TextInput, Button, AsyncStorage } from 'react-native' import { goHome } from './navigation' import { USER_KEY } from './config' export default class SignIn extends React.Component { state = { username: '', password: '' } onChangeText = (key, value) => { this.setState({ [key]: value }) } signIn = async () => { const { username, password } = this.state try { // login with provider const user = await AsyncStorage.setItem(USER_KEY, username) console.log('user successfully signed in!', user) goHome() } catch (err) { console.log('error:', err) } } render() { return ( <View style={styles.container}> <TextInput style={styles.input} placeholder='Username' autoCapitalize="none" autoCorrect={false} placeholderTextColor='white' onChangeText={val => this.onChangeText('username', val)} /> <TextInput style={styles.input} placeholder='Password' autoCapitalize="none" secureTextEntry={true} placeholderTextColor='white' onChangeText={val => this.onChangeText('password', val)} /> <Button title='Sign In' onPress={this.signIn} /> </View> ) } } const styles = StyleSheet.create({ input: { width: 350, fontSize: 18, fontWeight: '500', height: 55, backgroundColor: '#42A5F5', margin: 10, color: 'white', padding: 8, borderRadius: 14 }, container: { flex: 1, justifyContent: 'center', alignItems: 'center' } })
فایل SignIn.js
این کامپوننت شامل یک فرم ثبت نام ساده می باشد. در متد کلاسی signIn یک ثبت نام موفق را با تعیین مشخصه نام کاربری در AsyncStorage شبیهسازی کردهایم و کاربر را به صفحه Home هدایت میکنیم. اینک باید بتوانیم اپلیکیشن را اجرا کنیم:
react-native run-ios # or react-native run-android
کد نهایی این پروژه را میتوانید در این ریپوی گیتهاب ببینید.
با پلاتین همراه باشید.