کتابخانه React Native Navigation — راهنمای شروع به استفاده

۱۴۱ بازدید
آخرین به‌روزرسانی: ۲۰ شهریور ۱۴۰۲
زمان مطالعه: ۹ دقیقه
کتابخانه React Native Navigation — راهنمای شروع به استفاده

در این مطلب به معرفی روش ساخت اپلیکیشن‌های ری‌اکت با استفاده از نسخه کتابخانه React Native Navigation (+) می‌پردازیم. نسخه دوم کتابخانه React Native Navigation اخیراً انتشار یافته است. به همین مناسبت در این نوشته تلاش کرده‌ایم به معرفی و بررسی آن بپردازیم. این کتابخانه یک پیاده‌سازی از ناوبری نیتیو و نه یک پیاده‌سازی مبتنی بر جاوا اسکریپت است. این بدان معنی است که این کتابخانه به طور معمول عملکرد بالاتری دارد و از تعامل‌ها و گذار صفحه روان‌تری در مقایسه با دیگر راه‌حل‌هایی که پیاده‌سازی نیتیو ندارند برخوردار است.

نسخه 2 کتابخانه React Native Navigation در واقع یک بازنویسی از نسخه اول این کتابخانه است که برخی از مشکلات آن را که در انتشار اولیه پیدا شدند رفع کرده است. در این راهنما روش ساخت یک گردش کار احراز هویت واقعی را می‌سازیم که یک شبیه‌سازی از حالت احراز هویت با استفاده از AsyncStorage است. البته شما می‌توانید از هر ارائه‌دهنده سرویس احراز هویت که خودتان انتخاب می‌کنید بهره بگیرید.

ارزش استفاده از گردش کار احراز هویت به عنوان دمو در این راهنما آن است که می‌توانیم با سطح نسبتاً بزرگی از API مربوط به React Native Navigation آشنا شویم و با ناوبری مبتنی بر stack و tab کار کنیم. همچنین شیوه حل یک مسئله واقعی را در هنگام ساختن یک اپلیکیشن مشاهده خواهیم کرد که مسئله‌ی ساخت ناوبری برای ملاحظات احراز هویت کاربر است.

گردش کار چگونه است؟

کتابخانه Navigation ری‌اکت

هنگامی که اپلیکیشن بارگذاری می‌شود، یک کامپوننت مقداردهی (Initializing) ابتدایی را بارگذاری می‌کنیم. همزمان بررسی می‌کنیم که آیا کاربری در حافظه دستگاه ذخیره شده است یا نه. اگر کاربری در حافظه دستگاه موجود باشد، مسیر Home را در یک ناوبری مبتنی بر stack رندر می‌کنیم.

اگر کاربری در حافظه دستگاه وجود نداشته باشد، کامپوننت‌های auth (یعنی SignIn و SignUp) را در یک ناوبری مبتنی بر tab پیگیری می‌کنیم.

برای مشاهده تصویر در ابعاد اصلی روی آن کلیک کنید.

دقت کنید که این مقاله بخش اول یک مقاله دوبخشی است که در هر یک از بخش‌های آن مطالب زیر عرضه می‌شوند:

  • بخش اول: ایجاد گردش کار ناوبری و احراز هویت سر به سر با احراز هویت ساختگی برای استفاده با هر ارائه‌دهنده خدمات احراز هویت.
  • بخش دوم: تعویض احراز هویت ساختگی با احراز هویت واقعی با استفاده از Amazon Cognito

سرآغاز

در آغاز کار باید یک پروژه ری‌اکت نیتیو را با استفاده از React Native CLI بسازیم:

react-native init RNNav2

سپس از npm یا yarn برای نصب ناوبری ری‌اکت نیتیو بهره می‌گیریم:

npm install react-native-navigation@alpha
# or
yarn add react-native-navigation@alpha

اینک باید وابستگی‌های نیتیو را لینک کنیم و مقداری کد نیتیو نیز بنویسیم.

برای کسب راهنمایی در مورد روش یکپارچه‌سازی کتابخانه در iOS به این صفحه (+) مراجعه کنید. برای کسب راهنمایی در خصوص روش ادغام کتابخانه در سیستم عامل اندروید به این صفحه (+) رجوع کنید.

ایجاد فایل‌ها

در این مرحله فایل‌هایی که برای این اپلیکیشن لازم هستند را ایجاد می‌کنیم. ابتدا یک پوشه به نام 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 داریم.

فایل Screen2.js: این فایل شامل کامپوننت دیگری برای ناوبری به/از صفحه اصلی اپلیکیشن است که از ناوبری پشته‌ای stack بهره می‌گیرد.

ثبت کردن صفحه‌ها

در زمان استفاده از React Native Navigation باید هر یک از صفحه‌ها را که در اپلیکیشن ما استفاده خواهد شد ثبت کنیم.

به این منظور از متد registerComponent در کتابخانه React Native Navigation استفاده می‌کنیم. ما همه صفحه‌هایی را که می‌خواهیم مقداردهی کنیم، در یک تابع منفرد قرار می‌دهیم و آن را پیش از ایجاد root ناوبری خود فراخوانی می‌کنیم.

1// screens.js
2
3import {Navigation} from 'react-native-navigation';
4
5export function registerScreens() {
6  Navigation.registerComponent('Home', () => require('./Home').default);
7  Navigation.registerComponent('Initializing', (sc) => require('./Initializing').default);
8  Navigation.registerComponent('SignIn', () => require('./SignIn').default);
9  Navigation.registerComponent('SignUp', () => require('./SignUp').default);
10  Navigation.registerComponent('Screen2', () => require('./Screen2').default);
11}

در این کد یک تابع را ایجاد و اکسپورت کرده‌ایم که ()Navigation.registerComponent را روی هر کامپوننتی که می‌خواهیم در ناوبری خود داشته باشیم، فراخوانی می‌کند.

ثبت اپلیکیشن

سپس فایل index.js را طوری به‌روزرسانی می‌کنیم که پشته ناوبری ابتدایی اپلیکیشن تنظیم و مقداردهی شود.

1// index.js
2import {Navigation} from 'react-native-navigation';
3import {registerScreens} from './src/screens';
4
5registerScreens();
6
7Navigation.events().registerAppLaunchedListener(() => {
8  Navigation.setRoot({
9    root: {
10      component: {
11        name: 'Initializing'
12      }
13    },
14  });
15});

در کد فوق تابع registerScreens را ایمپورت و فراخوانی می‌کنیم.

همچنین ریشه ابتدایی پشته اپلیکیشن را با فراخوانی Navigation.setRoot تعیین می‌کنیم و مسیرهای اولیه را که می‌خواهیم اپلیکیشن ما رندر کند به آن ارسال می‌کنیم. در این مورد root یک کامپوننت منفرد، به نام صفحه Initializing خواهد بود.

ایجاد تابع‌های ناوبری

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

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

1// navigation.js
2import { Navigation } from 'react-native-navigation'
3
4export const goToAuth = () => Navigation.setRoot({
5  root: {
6    bottomTabs: {
7      id: 'BottomTabsId',
8      children: [
9        {
10          component: {
11            name: 'SignIn',
12            options: {
13              bottomTab: {
14                fontSize: 12,
15                text: 'Sign In',
16                icon: require('./signin.png')
17              }
18            }
19          },
20        },
21        {
22          component: {
23            name: 'SignUp',
24            options: {
25              bottomTab: {
26                text: 'Sign Up',
27                fontSize: 12,
28                icon: require('./signup.png')
29              }
30            }
31          },
32        },
33      ],
34    }
35  }
36});
37
38export const goHome = () => Navigation.setRoot({
39  root: {
40    stack: {
41      id: 'App',
42      children: [
43        {
44          component: {
45            name: 'Home',
46          }
47        }
48    ],
49    }
50  }
51})

تصاویری که برای برگه‌های فوق استفاده می‌کنیم، به صورت زیر هستند. شما می‌توانید آن‌ها را ذخیره کرده و مورد استفاده قرار دهید.

تصویر برگه ورود (SignIn):

تصویر برگه ثبت نام (SignUp):

در فایل navigation.js دو تابع وجود دارد:

  • goToAuth – این تابع پشته مسیر ریشه ما را به پیکربندی مسیر bottomTabs تنظیم می‌کند. هر برگه یک کامپوننت است که نام و برخی گزینه‌ها برای آن پیکربندی شده است.
  • goHome – این تابع پشته مسیر را به صورت ناوبری stack تعیین می‌کند و یک کامپوننت منفرد را به آرایه فرزندان یعنی کامپوننت Home ارسال می‌کند.

ذخیره‌سازی کلید AsyncStorage در یک فایل پیکربندی

ما به بررسی AsyncStorage می‌پردازیم تا ببینیم آیا کاربر قبلاً ثبت نام کرده است یا نه. این کار در چند فایل صورت می‌گیرد. کلید AsyncStorage را در یک فایل جداگانه ذخیره می‌کنیم تا بتوانیم آن را به سادگی مورد استفاده مجدد قرار دهیم.

1// config.js
2export const USER_KEY = 'USER_KEY'

ایجاد صفحات

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

فایل Initializing.js

برای مشاهده تصویر در ابعاد اصلی روی آن کلیک کنید.
1// Initializing.js
2import React from 'react'
3import {
4  View,
5  Text,
6  StyleSheet,
7  AsyncStorage
8} from 'react-native'
9
10import { goToAuth, goHome } from './navigation'
11
12import { USER_KEY } from './config'
13
14export default class Initialising extends React.Component {
15  async componentDidMount() {
16    try {
17      const user = await AsyncStorage.getItem(USER_KEY)
18      console.log('user: ', user)
19      if (user) {
20        goHome()
21      } else {
22        goToAuth()
23      }
24    } catch (err) {
25      console.log('error: ', err)
26      goToAuth()
27    }
28  }
29
30  render() {
31    return (
32      <View style={styles.container}>
33        <Text style={styles.welcome}>Loading</Text>
34      </View>
35    )
36  }
37}
38
39const styles = StyleSheet.create({
40  welcome: {
41    fontSize: 28
42  },
43  container: {
44    flex: 1,
45    justifyContent: 'center',
46    alignItems: 'center'
47  }
48})

اگر به کلاس componentDidMount نگاه کنید می‌بینید که اغلب کارهای عمده در این فایل صورت می‌گیرند. ما AsyncStorage را بررسی می‌کنیم تا ببینیم آیا کاربری در حافظه دستگاه ذخیره شده است یا نه و در صورتی که چنین حالتی وجود داشته باشد صفحه Home را بارگذاری می‌کنیم و در غیر این صورت مسیرهای Auth یعنی SignIn و SignUp را بارگذاری خواهیم کرد.

زمانی که کلاس componentDidMount منطق مورد نیاز برای بررسی ذخیره شدن کاربر در دستگاه را اجرا می‌کند؛ یک پیام بارگذاری را برای کاربری نمایش می‌دهیم. سپس پشته مسیر را بر مبنای این که کاربر موجود است یا نه ریست می‌کنیم.

فایل Home.js

برای مشاهده تصویر در ابعاد اصلی روی آن کلیک کنید.
1// Home.js
2import React from 'react'
3import {
4  View,
5  Text,
6  Button,
7  StyleSheet,
8  AsyncStorage
9} from 'react-native'
10import { goToAuth } from './navigation'
11import {Navigation} from 'react-native-navigation';
12
13import { USER_KEY } from './config'
14
15export default class Home extends React.Component {
16  static get options() {
17    return {
18      topBar: {
19        title: {
20          text: 'Home'
21        },
22      }
23    };
24  }
25  logout = async () => {
26    try {
27      await AsyncStorage.removeItem(USER_KEY)
28      goToAuth()
29    } catch (err) {
30      console.log('error signing out...: ', err)
31    }
32  }
33  render() {
34    return (
35      <View style={styles.container}>
36        <Text>Hello from Home screen.</Text>
37        <Button
38          onPress={this.logout}
39          title="Sign Out"
40        />
41        <Button
42          onPress={() => {
43            Navigation.push(this.props.componentId, {
44              component: {
45                name: 'Screen2',
46              }
47            });
48          }}
49          title="View next screen"
50        />
51      </View>
52    )
53  }
54}
55
56const styles = StyleSheet.create({
57  container: {
58    flex: 1,
59    justifyContent: 'center',
60    alignItems: 'center'
61  }
62})

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

یک نکته متفاوت که باید در این بخش مورد اشاره قرار دهیم، روش فراخوانی متدهای ناوبری است. ما به جای استفاده از props مانند نسخه قدیمی (this.props.navigator.push) یعنی API مربوط به Navigation را ایمپورت کرده و Navigation.push را فراخوانی می‌کنیم.

همچنین متوجه یک تابع کلاس استاتیک به نام ()get options می‌شویم. این تابع را می‌توان به تعریف کامپوننت ری‌اکت صفحه اضافه کرد و سبک‌بندی و مشخصه‌ها را به ظاهر ناوبری افزود. در مورد مثال مورد بررسی، ما صرفاً یک مشخصه عنوان برای topBar استفاده کرده‌ایم.

فایل Screen2.js

برای مشاهده تصویر در ابعاد اصلی روی آن کلیک کنید.
1import React from 'react'
2import {
3  View,
4  Text,
5  Button,
6  StyleSheet,
7} from 'react-native'
8import {Navigation} from 'react-native-navigation';
9
10export default class Screen2 extends React.Component {
11  static get options() {
12    return {
13      topBar: {
14        title: {
15          text: 'Screen 2'
16        },
17      }
18    };
19  }
20  render() {
21    return (
22      <View style={styles.container}>
23        <Text>Screen 2</Text>
24        <Button
25          onPress={() => Navigation.pop(this.props.componentId)}
26          title="Go Back"
27        />
28      </View>
29    )
30  }
31}
32
33const styles = StyleSheet.create({
34  container: {
35    flex: 1,
36    justifyContent: 'center',
37    alignItems: 'center'
38  }
39})

این فایل یک صفحه کاملاً ابتدایی است که صرفاً برای نمایش ناوبری در یک ناوبری پشته‌ای از صفحه Home مورد استفاده قرار می‌دهیم. نکته‌ای که باید اشاره کرد، شیوه فراخوانی تابع Navigation.pop است. این روش نیز از نسخه قدیمی API که در آن از props استفاده می‌شد (this.props.navigator.pop) متفاوت است و در نسخه 2 از API Navigation ایمپورت شده از کتابخانه React Native Navigation با نام استفاده می‌کنیم.

فایل SignUp.js

برای مشاهده تصویر در ابعاد اصلی روی آن کلیک کنید.
1// SignUp.js
2import React from 'react'
3import {
4  View,
5  Button,
6  TextInput,
7  StyleSheet
8} from 'react-native'
9
10export default class SignUp extends React.Component {
11  state = {
12    username: '', password: '', email: '', phone_number: ''
13  }
14  onChangeText = (key, val) => {
15    this.setState({ [key]: val })
16  }
17  signUp = async () => {
18    const { username, password, email, phone_number } = this.state
19    try {
20      // here place your signup logic
21      console.log('user successfully signed up!: ', success)
22    } catch (err) {
23      console.log('error signing up: ', err)
24    }
25  }
26 
27  render() {
28    return (
29      <View style={styles.container}>
30        <TextInput
31          style={styles.input}
32          placeholder='Username'
33          autoCapitalize="none"
34          placeholderTextColor='white'
35          onChangeText={val => this.onChangeText('username', val)}
36        />
37        <TextInput
38          style={styles.input}
39          placeholder='Password'
40          secureTextEntry={true}
41          autoCapitalize="none"
42          placeholderTextColor='white'
43          onChangeText={val => this.onChangeText('password', val)}
44        />
45        <TextInput
46          style={styles.input}
47          placeholder='Email'
48          autoCapitalize="none"
49          placeholderTextColor='white'
50          onChangeText={val => this.onChangeText('email', val)}
51        />
52        <TextInput
53          style={styles.input}
54          placeholder='Phone Number'
55          autoCapitalize="none"
56          placeholderTextColor='white'
57          onChangeText={val => this.onChangeText('phone_number', val)}
58        />
59        <Button
60          title='Sign Up'
61          onPress={this.signUp}
62        />
63      </View>
64    )
65  }
66}
67
68const styles = StyleSheet.create({
69  input: {
70    width: 350,
71    height: 55,
72    backgroundColor: '#42A5F5',
73    margin: 10,
74    padding: 8,
75    color: 'white',
76    borderRadius: 14,
77    fontSize: 18,
78    fontWeight: '500',
79  },
80  container: {
81    flex: 1,
82    justifyContent: 'center',
83    alignItems: 'center'
84  }
85})

فایل SignUp.js در حال حاضر صرفاً یک محفظه خالی برای فرم ثبت نام محسوب می‌شود. می‌توان از این محفظه برای پیاده‌سازی سرویس احراز هویت مورد استفاده بهره گرفت. در بخش بعدی این مقاله ما این فایل را طوری به‌روزرسانی می‌کنیم که یک فرم ثبت نام واقعی با استفاده از AWS Amplify و Amazon Cognito باشد.

فایل SignIn.js

برای مشاهده تصویر در ابعاد اصلی روی لینک زیر کلیک کنید.
1// SignIn.js
2import React from 'react'
3import {
4  View,
5  Text,
6  StyleSheet,
7  TextInput,
8  Button,
9  AsyncStorage
10} from 'react-native'
11
12import { goHome } from './navigation'
13import { USER_KEY } from './config'
14
15export default class SignIn extends React.Component {
16  state = {
17    username: '', password: ''
18  }
19  onChangeText = (key, value) => {
20    this.setState({ [key]: value })
21  }
22  signIn = async () => {
23    const { username, password } = this.state
24    try {
25       // login with provider
26       const user = await AsyncStorage.setItem(USER_KEY, username)
27       console.log('user successfully signed in!', user)
28       goHome()
29    } catch (err) {
30      console.log('error:', err)
31    }
32  }
33  render() {
34    return (
35      <View style={styles.container}>
36        <TextInput
37          style={styles.input}
38          placeholder='Username'
39          autoCapitalize="none"
40          autoCorrect={false}
41          placeholderTextColor='white'
42          onChangeText={val => this.onChangeText('username', val)}
43        />
44        <TextInput
45          style={styles.input}
46          placeholder='Password'
47          autoCapitalize="none"
48          secureTextEntry={true}
49          placeholderTextColor='white'
50          onChangeText={val => this.onChangeText('password', val)}
51        />
52        <Button
53          title='Sign In'
54          onPress={this.signIn}
55        />
56      </View>
57    )
58  }
59}
60
61const styles = StyleSheet.create({
62  input: {
63    width: 350,
64    fontSize: 18,
65    fontWeight: '500',
66    height: 55,
67    backgroundColor: '#42A5F5',
68    margin: 10,
69    color: 'white',
70    padding: 8,
71    borderRadius: 14
72  },
73  container: {
74    flex: 1,
75    justifyContent: 'center',
76    alignItems: 'center'
77  }
78})

فایل SignIn.js

این کامپوننت شامل یک فرم ثبت نام ساده است. در متد کلاسی signIn یک ثبت نام موفق را با تعیین مشخصه نام کاربری در AsyncStorage شبیه‌سازی کرده‌ایم و کاربر را به صفحه Home هدایت می‌کنیم. اینک باید بتوانیم اپلیکیشن را اجرا کنیم:

react-native run-ios
# or
react-native run-android

کد نهایی این پروژه را می‌توانید در این ریپوی گیت‌هاب (+) ملاحظه کنید.

برای مطالعه قسمت بعدی این مطلب می‌توانید روی لینک زیر کلیک کنید:

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۲ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
react-native-training
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *