معالجة تصاعد وإلغاء تثبيت مسارات الملاحة في React Native

نشرت: 2022-03-10
ملخص سريع ↬ غالبًا ما تحتاج إلى مجموعتين مختلفتين من حزم التنقل للمصادقة المسبقة واللاحقة للمستخدم. عادة ، لمشاهدة المزيد من المحتوى ، يجب أن تتم المصادقة عليك بطريقة ما. لنلقِ نظرة على كيفية تركيب مكدس تنقل وإلغاء تحميله بناءً على شرط مستوفٍ في React Native.

في هذه المقالة ، سنستعرض طرق التنقل المتصاعدة وإلغاء تركيبها في React Native. السلوك المتوقع لتطبيقك هو أنه بمجرد استيفاء شرط المصادقة ، تتوفر مجموعة جديدة من مسارات التنقل فقط للمستخدمين الذين قاموا بتسجيل الدخول ، في حين أن الشاشات الأخرى التي تم عرضها قبل إزالة المصادقة ولا يمكن إرجاعها إليها ما لم يقوم المستخدم بتسجيل الخروج من التطبيق.

للأمان في تطبيقك ، توفر لك المسارات المحمية طريقة لعرض معلومات / محتوى معين فقط على تطبيقك لمستخدمين محددين ، مع تقييد الوصول من الأشخاص غير المصرح لهم.

سنعمل مع Expo لهذا المشروع لأنه سيساعدنا في التركيز على المشكلة المطروحة بدلاً من القلق بشأن الكثير من الإعدادات. يمكن اتباع نفس الخطوات بالضبط في هذه المقالة لتطبيق React Native العاري.

أنت بحاجة إلى بعض الإلمام بـ JavaScript و React Native لمتابعة هذا البرنامج التعليمي. إليك بعض الأشياء المهمة التي يجب أن تكون على دراية بها بالفعل:

  • المكونات المخصصة في React Native (كيفية إنشاء المكونات واستلامها وتمريرها واستخدامها في أحد المكونات). اقرأ أكثر.
  • رد فعل الملاحة. اقرأ أكثر.
  • Stack Navigator في React Native. اقرأ أكثر.
  • المعرفة الأساسية لمكونات React Native Core ( <View/> ، <Text/> ، إلخ). اقرأ أكثر.
  • تفاعل AsyncStorage الأصلي. اقرأ أكثر.
  • السياق API. اقرأ أكثر.

إعداد المشروع والمصادقة الأساسية

إذا كنت جديدًا في استخدام إكسبو ولا تعرف كيفية تثبيت إكسبو ، فقم بزيارة الوثائق الرسمية. بمجرد اكتمال التثبيت ، امض قدمًا لتهيئة مشروع React Native جديد مع expo من موجه الأوامر الخاص بنا:

 expo init navigation-project

سيتم تقديمك مع بعض الخيارات لاختيار الطريقة التي تريد أن يكون الإعداد الأساسي بها:

رد فعل الإعداد الأساسي للمشروع الأصلي
(معاينة كبيرة)

في حالتنا ، دعنا نحدد الخيار الأول لإعداد مشروعنا كمستند فارغ. الآن ، انتظر حتى يكتمل تثبيت تبعيات JavaScript.

بمجرد إعداد تطبيقنا ، يمكننا تغيير دليلنا إلى دليل مشروعنا الجديد وفتحه في محرر الكود المفضل لديك. نحتاج إلى تثبيت المكتبة التي سنستخدمها لـ AsyncStorage ومكتبات التنقل الخاصة بنا. داخل مجلد المجلد في الجهاز الطرفي ، الصق الأمر أعلاه واختر نموذجًا (سيعمل blank ) لتثبيت تبعيات مشروعنا.

لنلقِ نظرة على الغرض من كل من هذه التبعيات:

  • @ رد فعل المجتمع الأصلي / تخزين غير متزامن
    مثل localStorage على الويب ، فهي واجهة برمجة تطبيقات أصلية من React لاستمرار البيانات على جهاز في أزواج مفتاح - قيمة.
  • @ رد فعل المجتمع الأصلي / عرض مقنع ، رد فعل الشاشات الأصلية ، رد فعل أصلي لفتة مقبض
    هذه التبعيات هي أدوات مساعدة أساسية يستخدمها معظم الملاحين لإنشاء بنية التنقل في التطبيق. (اقرأ المزيد في بدء استخدام التنقل الأصلي في React.)
  • @ رد فعل التنقل / أصلي
    هذه هي التبعية لـ React Native navigation.
  • @ رد فعل التنقل / المكدس
    هذه هي التبعية للتنقل المكدس في React Native.
 npm install @react-native-community/async-storage @react-native-community/masked-view @react-navigation/native @react-navigation/stack react-native-screens react-native-gesture-handle

لبدء التطبيق ، استخدم expo start من دليل التطبيق في جهازك الطرفي. بمجرد بدء تشغيل التطبيق ، يمكنك استخدام تطبيق expo من هاتفك المحمول لمسح الرمز الشريطي وعرض التطبيق ، أو إذا كان لديك محاكي android / محاكي IOS ، يمكنك فتح التطبيق من خلالها من أداة مطور المعرض التي يفتح في متصفحك عند بدء تطبيق المعرض. بالنسبة لأمثلة الصور في هذه المقالة ، سنستخدم Genymotions لمعرفة النتيجة. إليك ما ستبدو عليه النتيجة النهائية في Genymotions:

النتيجة النهائية في Genymotions
(معاينة كبيرة)

هياكل المجلد

دعنا ننشئ بنية المجلد الخاصة بنا من البداية حتى يسهل علينا العمل بها أثناء المضي قدمًا:

نحتاج إلى مجلدين أولاً:

  • سياق الكلام
    سيحتوي هذا المجلد على سياق تطبيقنا بالكامل حيث سنعمل مع Context API لإدارة الحالة العالمية.
  • الآراء
    سيحتوي هذا المجلد على كل من مجلد التنقل وطرق العرض الخاصة بالشاشات المختلفة.

انطلق وأنشئ المجلدين في دليل مشروعك.

داخل مجلد السياق ، أنشئ مجلدًا يسمى authContext وأنشئ ملفين داخل مجلد authContext :

  • AuthContext.js ،
  • AuthState.js .

سنحتاج إلى هذه الملفات عندما نبدأ العمل مع Context API.

انتقل الآن إلى مجلد العروض الذي أنشأناه وأنشئ مجلدين آخرين بداخله ، وهما:

  • الملاحة
  • الشاشات .

الآن ، لم ننتهي بعد ، داخل مجلد الشاشات ، قم بإنشاء هذين المجلدين الآخرين:

  • شاشات postAuthScreens ،
  • شاشات preAuthScreens .

إذا اتبعت إعداد المجلد بشكل صحيح ، فهذا هو الشكل الذي يجب أن تبدو عليه بنية المجلد في الوقت الحالي:

هيكل المجلد
(معاينة كبيرة)
المزيد بعد القفز! أكمل القراءة أدناه ↓

إنشاء الشاشة الأولى لدينا

لنقم الآن بإنشاء شاشتنا الأولى ونطلق عليها اسم welcomeScreen.js داخل مجلد preAuthScreens .

preAuthScreens> welcomeScreen.js

هذا هو محتوى ملف welcomeScreen.js الخاص بنا:

 import React from 'react'; import { View, Text, Button, StyleSheet, TextInput } from 'react-native'; const WelcomeScreen = () => { const onUserAuthentication = () => { console.log("User authentication button clicked") } return ( <View style={styles.container}> <Text style={styles.header}>Welcome to our App!</Text> <View> <TextInput style={styles.inputs} placeholder="Enter your email here.." /> <TextInput style={styles.inputs} secureTextEntry={true} placeholder="Enter your password here.." /> <Button title="AUTHENTICATE" onPress={onUserAuthentication} /> </View> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, header: { fontSize: 25, fontWeight: 'bold', marginBottom: 30 }, inputs: { width: 300, height: 40, marginBottom: 10, borderWidth: 1, } }) export default WelcomeScreen

إليك ما فعلناه في مقطع التعليمات البرمجية أعلاه:

أولاً ، قمنا باستيراد الأشياء التي نحتاجها من مكتبة React Native ، وهي View و Text و Button و TextInput . بعد ذلك ، أنشأنا مكوننا الوظيفي WelcomeScreen .

ستلاحظ أننا استوردنا StyleSheet من React Native واستخدمناها لتحديد أنماط رأسنا وأيضًا <TextInput /> .

أخيرًا ، نقوم بتصدير مكون WelcomeScreen في الجزء السفلي من الكود.

الآن وقد انتهينا من هذا ، دعنا نجعل هذا المكون يعمل كما هو متوقع باستخدام خطاف useState لتخزين قيم المدخلات وتحديث حالاتها في أي وقت يحدث تغيير في حقول الإدخال. سنجلب أيضًا استيراد الخطاف useCallback من React لأننا سنحتاجه لاحقًا للاحتفاظ بوظيفة.

أولاً ، بينما لا نزال في مكون WelcomeScreen ، نحتاج إلى استيراد useState و useCallback من React.

 import React, { useState, useCallback } from 'react';

الآن داخل المكون الوظيفي WelcomeScreen ، دعنا ننشئ حالتين للبريد الإلكتروني وكلمة المرور على التوالي:

 ... const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( ... ) } ...

بعد ذلك ، نحتاج إلى تعديل <TextInput /> بنا حتى نحصل على قيمتها من حالاتها الخاصة وتحديث حالتها عند تحديث قيمة الإدخال:

 import React, { useState, useCallback } from 'react'; import { View, Text, Button, StyleSheet, TextInput } from 'react-native'; const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') const onInputChange = (value, setState) => { setState(value); } return ( <View> ... <View> <TextInput style={styles.inputs} placeholder="Enter your email here.." value={email} onChangeText={(value) => onInputChange(value, setEmail)} /> <TextInput style={styles.inputs} secureTextEntry={true} placeholder="Enter your password here.." value={password} onChangeText={(value) => onInputChange(value, setPassword)} /> ... </View> </View> ) } ...

في الكود أعلاه ، هذا ما فعلناه:

  • لقد وضعنا value كل مدخلات نصية للإشارة إلى حالة كل منها.
  • أضفنا معالج onChangeText إلى مدخلات النص لدينا. يعمل هذا في أي وقت يتم فيه إدخال قيمة جديدة أو حذفها من حقول الإدخال.
  • لقد أطلقنا على دالة onInputChange التي تقبل وسيطين:
    • يتم توفير value الحالية بواسطة معالج onChangeText .
    • محدد الحالة الذي يجب تحديثه (بالنسبة لحقل الإدخال الأول ، نمرر setEmail والثاني نمرر setPassword .
    • أخيرًا ، نكتب دالة onInputChange بنا ، وتقوم وظيفتنا بعمل شيء واحد فقط: إنها تقوم بتحديث الحالات المعنية بالقيمة الجديدة.

الشيء التالي الذي نحتاج إلى العمل عليه هو وظيفة onUserAuthentication() التي يتم استدعاؤها كلما تم النقر فوق الزر الخاص بإرسال النموذج.

من الناحية المثالية ، يجب أن يكون المستخدم قد أنشأ بالفعل حسابًا وسيشمل تسجيل الدخول بعض منطق الواجهة الخلفية من نوع ما للتحقق من وجود المستخدم ثم تعيين رمز مميز للمستخدم. في حالتنا ، نظرًا لأننا لا نستخدم أي واجهة خلفية ، فسننشئ كائنًا يحمل تفاصيل تسجيل دخول المستخدم الصحيحة ، ثم نصدق فقط على المستخدم عندما تتطابق القيم التي يدخلونها مع قيمنا الثابتة من كائن تسجيل الدخول email password التي سنقوم بها يزيد.

هذا هو الكود الذي نحتاجه للقيام بذلك:

 ... const correctAuthenticationDetails = { email: '[email protected]', password: 'password' } const WelcomeScreen = () => { ... // This function gets called when the `AUTHENTICATE` button is clicked const onUserAuthentication = () => { if ( email !== correctAuthenticationDetails.email || password !== correctAuthenticationDetails.password ) { alert('The email or password is incorrect') return } // In here, we will handle what happens if the login details are // correct } ... return ( ... ) } ...

من أول الأشياء التي correctAuthenticationDetails في الكود أعلاه أننا حددنا تفاصيل المصادقة الصحيحة (وهو كائن يحمل تفاصيل تسجيل الدخول الصحيحة التي نتوقع أن يوفرها المستخدم) خارج المكون الوظيفي WelcomeScreen() .

بعد ذلك ، كتبنا محتوى وظيفة onUserAuthentication() واستخدمنا عبارة شرطية للتحقق مما إذا كان email أو password المحفوظة في الحالات المعنية لا تتطابق مع تلك التي قدمناها في كائننا.

إذا كنت ترغب في معرفة ما فعلناه حتى الآن ، فاستورد مكون WelcomeScreen إلى App.js على النحو التالي:

افتح ملف App.js وضع هذا واستبدل الكود بالكامل بهذا:

 import { StatusBar } from 'expo-status-bar'; import React from 'react'; import { View } from 'react-native'; import WelcomeScreen from './views/screens/preAuthScreens/welcomeScreen'; export default function App() { return ( <View> <StatusBar /> <WelcomeScreen /> </View> ); }

بالنظر عن كثب إلى الكود أعلاه ، سترى أن ما فعلناه هو استيراد مكون WelcomeScreen ثم استخدامه في وظيفة App() .

إليك ما تبدو عليه نتيجة برنامج WelcomeScreen الخاص بنا:

نتيجة WelcomeScreen
(معاينة كبيرة)

الآن بعد أن انتهينا من بناء مكون WelcomeScreen ، دعنا نمضي قدمًا ونبدأ العمل مع Context API لإدارة حالتنا العالمية.

لماذا السياق API؟

باستخدام واجهة برمجة تطبيقات السياق ، لا نحتاج إلى تثبيت أي مكتبة إضافية في ReactJS ، فهي أقل إرهاقًا في الإعداد ، وهي واحدة من أكثر الطرق شيوعًا للتعامل مع الحالة العالمية في ReactJS. لإدارة الحالة خفيفة الوزن ، إنه اختيار جيد.

خلق سياقنا

إذا كنت تتذكر ، فقد أنشأنا مجلد سياق في وقت سابق وأنشأنا مجلدًا فرعيًا بداخله يسمى authContext .

الآن دعنا ننتقل إلى ملف AuthContext.js في مجلد authContext وننشئ سياقنا:

السياق> authContext> AuthContext.js

 import React, { createContext } from 'react'; const AuthContext = createContext(); export default AuthContext;

AuthContext الذي أنشأناه للتو يحمل قيمة حالة loading وقيم حالة userToken . حاليًا ، في createContext التي أعلناها في كتلة التعليمات البرمجية أعلاه ، لم نقم بتهيئة أي قيم افتراضية هنا ، لذا فإن سياقنا غير undefined حاليًا. مثال على قيمة سياق المصادقة يمكن أن تكون {loading: false, userToken: 'abcd}

يحتوي ملف AuthState.js على منطق واجهة برمجة تطبيقات السياق وقيم الحالة الخاصة بها. يمكن استدعاء الوظائف المكتوبة هنا من أي مكان في تطبيقنا وعندما تقوم بتحديث القيم في الحالة ، يتم تحديثها عالميًا أيضًا.

أولاً ، لنحضر جميع الواردات التي سنحتاجها في هذا الملف:

السياق> AuthContext> AuthState.js

 import React, { useState } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage';

لقد استوردنا الخطاف useState() من ReactJS للاحتفاظ بحالاتنا ، واستوردنا ملف AuthContext الذي أنشأناه أعلاه لأن هذا هو المكان الذي تتم فيه تهيئة سياق المصادقة الفارغ الخاص بنا وسنحتاج إلى استخدامه كما سترى لاحقًا أثناء تقدمنا ، أخيرًا نستورد حزمة AsyncStorage (على غرار localStorage للويب).

AsyncStorage هي واجهة برمجة تطبيقات أصلية من React تتيح لك الاحتفاظ بالبيانات دون اتصال بالإنترنت عبر الجهاز في تطبيق React Native.

 ... const AuthState = (props) => { const [userToken, setUserToken] = useState(null); const [isLoading, setIsLoading] = useState(true); const onAuthentication = async() => { const USER_TOKEN = "drix1123q2" await AsyncStorage.setItem('user-token', USER_TOKEN); setUserToken(USER_TOKEN); console.warn("user has been authenticated!") } return ( <AuthContext.Provider value={{ onAuthentication, }} > {props.children} </AuthContext.Provider> ) } export default AuthState;

في مقطع التعليمات البرمجية أعلاه ، إليك ما فعلناه:

  • أعلنا عن حالتين لكل من userToken و isLoading . سيتم استخدام حالة userToken لتخزين الرمز المميز المحفوظ في AsyncStorage ، بينما سيتم استخدام حالة isLoading لتتبع حالة التحميل (يتم تعيينها في البداية على " true "). سنكتشف المزيد حول استخدام هاتين الحالتين أثناء تقدمنا.

  • بعد ذلك ، كتبنا onAuthentication() بنا. هذه الوظيفة هي وظيفة غير welcomeScreen.jsx async لن يتم استدعاء هذه الوظيفة إلا إذا كان البريد الإلكتروني وكلمة المرور اللذين قدمهما المستخدم يطابقان كائن تفاصيل المستخدم الصحيح الذي قدمناه. عادةً ما يحدث أثناء المصادقة هو إنشاء رمز مميز للمستخدم بعد مصادقة المستخدم على الواجهة الخلفية باستخدام حزمة مثل JWT ، ويتم إرسال هذا الرمز المميز إلى الواجهة الأمامية. نظرًا لأننا لن ندخل في كل ذلك لهذا البرنامج التعليمي ، فقد أنشأنا رمزًا مميزًا ثابتًا واحتفظنا به في متغير يسمى USER_TOKEN .

  • بعد ذلك ، نستخدم الكلمة الأساسية await لتعيين رمز المستخدم الخاص بنا على AsyncStorage مع الاسم user-token . يتم استخدام عبارة console.warn() فقط للتحقق من أن كل شيء سار على ما يرام ، ويمكنك إزالته متى شئت.

  • أخيرًا ، نقوم بتمرير وظيفة onAuthenticated بنا كقيمة داخل <AuthContext.Provider> حتى نتمكن من الوصول إلى الوظيفة واستدعاءها من أي مكان في تطبيقنا.

الشاشات> المصادقة المسبقة> welcomeScreen.js

أولاً ، قم باستيراد useContext من ReactJS واستيراد AuthContext من ملف AuthContext.js .

 import React, { useState, useContext } from 'react'; import AuthContext from '../../../context/authContext/AuthContext' ...

الآن ، داخل المكون الوظيفي welcomeScreen() ، دعنا نستخدم السياق الذي أنشأناه:

 ... const WelcomeScreen = () => { const { onAuthentication } = useContext(AuthContext) const onUserAuthentication = () => { if ( email !== correctAuthenticationDetails.email || password !== correctAuthenticationDetails.password ) { alert('The email or password is incorrect') return } onAuthentication() } return ( ... ) } ...

في كتلة التعليمات البرمجية أعلاه ، قمنا بتدمير وظيفة onAuthentication من AuthContext الخاصة بنا ، ثم قمنا بتسميتها داخل وظيفة onUserAuthentication() console.log() الذي كان موجودًا من قبل.

في الوقت الحالي ، سيؤدي هذا إلى ظهور خطأ لأننا لا نملك حق الوصول إلى AuthContext . لاستخدام AuthContext في أي مكان في التطبيق الخاص بك ، نحتاج إلى التفاف ملف المستوى الأعلى في تطبيقنا مع AuthState (في حالتنا ، هو ملف App.js ).

انتقل إلى ملف App.js واستبدل الكود هناك بهذا:

 import React from 'react'; import WelcomeScreen from './views/screens/preAuthScreens/welcomeScreen'; import AuthState from './context/authContext/AuthState' export default function App() { return ( <AuthState> <WelcomeScreen /> </AuthState> ); }

لقد قطعنا شوطا طويلا وانتهينا من هذا القسم. قبل أن ننتقل إلى القسم التالي حيث قمنا بإعداد التوجيه ، فلنقم بإنشاء شاشة جديدة. الشاشة التي نحن بصدد إنشائها ستكون ملف HomeScreen.js الذي من المفترض أن يظهر فقط بعد مصادقة ناجحة.

انتقل إلى: الشاشات> postAuth .

قم بإنشاء ملف جديد يسمى HomeScreen.js . إليك رمز ملف HomeScreen.js :

الشاشات> postAuth> HomeScreen.js

 import React from 'react'; import { View, Text, Button, StyleSheet } from 'react-native'; const HomeScreen = () => { const onLogout = () => { console.warn("Logout button cliked") } return ( <View style={styles.container}> <Text>Now you're authenticated! Welcome!</Text> <Button title="LOG OUT" onPress={onLogout} /> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, }) export default HomeScreen

في الوقت الحالي ، يحتوي زر تسجيل الخروج على عبارة وهمية console.log() . لاحقًا ، سننشئ وظيفة تسجيل الخروج ونمررها إلى الشاشة من سياقنا.

إعداد طرقنا

نحتاج إلى إنشاء ثلاثة (3) ملفات داخل مجلد التنقل الخاص بنا:

  • postAuthNavigator.js ،
  • preAuthNavigator.js ،
  • AppNavigator.js .

بمجرد إنشاء هذه الملفات الثلاثة ، انتقل إلى ملف preAuthNaviagtor.js الذي أنشأته للتو واكتب هذا:

التنقل> preAuthNavigator.js

 import React from "react"; import { createStackNavigator } from "@react-navigation/stack"; import WelcomeScreen from "../screens/preAuthScreens/welcomeScreen"; const PreAuthNavigator = () => { const { Navigator, Screen } = createStackNavigator(); return ( <Navigator initialRouteName="Welcome"> <Screen name="Welcome" component={WelcomeScreen} /> </Navigator> ) } export default PreAuthNavigator;

في الملف أعلاه ، إليك ما فعلناه:

  • لقد استوردنا createStackNavigator من @react-navigation/stack الذي نستخدمه للتنقل المكدس. يوفر createStackNavigator طريقة لتطبيقك للانتقال بين الشاشات حيث يتم وضع كل شاشة جديدة أعلى حزمة. بشكل افتراضي ، يتم تكوين متصفح المكدس ليحصل على الشكل والمظهر المألوفين لنظامي التشغيل iOS و Android: تنزلق الشاشات الجديدة من اليمين على نظام iOS ، وتتلاشى من الأسفل على Android. انقر هنا إذا كنت تريد معرفة المزيد عن متصفح المكدس في React Native.
  • لقد دمرنا Navigator Screen من createStackNavigator() .
  • في بيان العودة الخاص بنا ، أنشأنا التنقل باستخدام <Navigator/> وأنشأنا شاشتنا مع <Screen/> . هذا يعني أنه إذا كانت لدينا شاشات متعددة يمكن الوصول إليها قبل المصادقة ، فسيكون لدينا العديد من علامات <Screen/> هنا تمثلها.
  • أخيرًا ، نقوم بتصدير مكون PreAuthNavigator بنا.

دعونا نفعل شيئًا مشابهًا لملف postAuthNavigator.js .

التنقل> postAuthNavigator.js

 import React from "react"; import { createStackNavigator } from "@react-navigation/stack"; import HomeScreen from "../screens/postAuthScreens/HomeScreen"; const PostAuthNavigator = () => { const { Navigator, Screen} = createStackNavigator(); return ( <Navigator initialRouteName="Home"> <Screen name="Home" component={HomeScreen} /> </Navigator> ) } export default PostAuthNavigator;

كما نرى في الكود أعلاه ، فإن الاختلاف الوحيد بين preAuthNavigator.js و postAuthNavigator.js هو الشاشة التي يتم عرضها. بينما تأخذ الأولى شاشة WelcomeScreen ، تأخذ postAuthNavigator.js الشاشة HomeScreen .

لإنشاء AppNavigator.js الخاص بنا ، نحتاج إلى إنشاء بعض الأشياء.

نظرًا لأن AppNavigator.js هو المكان الذي سنقوم بالتبديل فيه والتحقق من المسار الذي سيكون متاحًا للوصول إليه من قبل المستخدم ، فنحن بحاجة إلى عدة شاشات حتى يعمل هذا بشكل صحيح ، دعنا نحدد الأشياء التي نحتاج إلى إنشائها أولاً:

  1. TransitionScreen.js
    أثناء تحديد التطبيق للتنقل الذي سيتم تحميله ، نريد ظهور شاشة انتقال. عادةً ما تكون شاشة الانتقال عبارة عن قرص تحميل أو أي رسوم متحركة مخصصة أخرى يتم اختيارها للتطبيق ، ولكن في حالتنا ، سنستخدم علامة <Text/> أساسية لعرض loading… .
  2. checkAuthenticationStatus()
    هذه الوظيفة هي ما سنطلبه للتحقق من حالة المصادقة التي ستحدد أي حزمة تنقل سيتم تركيبها. سننشئ هذه الوظيفة في سياقنا ونستخدمها في Appnavigator.js .

الآن ، دعنا نمضي قدمًا وننشئ ملف TransitionScreen.js الخاص بنا.

الشاشات> TransitionScreen.js

 import React from 'react'; import { Text, View } from 'react-native'; const TransitionScreen = () => { return ( <View> <Text>Loading...</Text> </View> ) } export default TransitionScreen

شاشة الانتقال لدينا هي مجرد شاشة بسيطة تعرض نص التحميل. سنرى مكان استخدام هذا أثناء المضي قدمًا في هذه المقالة.

بعد ذلك ، دعنا نذهب إلى AuthState.js الخاص بنا checkAuthenticationStatus() :

السياق> authContext> AuthState.js

 import React, { useState, useEffect } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage'; const AuthState = (props) => { const [userToken, setUserToken] = useState(null); const [isLoading, setIsLoading] = useState(true); ... useEffect(() => { checkAuthenticationStatus() }, []) const checkAuthenticationStatus = async () => { try { const returnedToken = await AsyncStorage.getItem('user-toke n'); setUserToken(returnedToken); console.warn('User token set to the state value) } catch(err){ console.warn(`Here's the error that occured while retrievin g token: ${err}`) } setIsLoading(false) } const onAuthentication = async() => { ... } return ( <AuthContext.Provider value={{ onAuthentication, userToken, isLoading, }} > {props.children} </AuthContext.Provider> ) } export default AuthState;

في كتلة التعليمات البرمجية أعلاه ، كتبنا وظيفة checkAuthenticationStatus() . في وظيفتنا ، إليك ما نقوم به:

  • استخدمنا الكلمة الأساسية await للحصول على رمزنا المميز من AsyncStorage . باستخدام AsyncStorage ، إذا لم يتم توفير رمز مميز ، فسيتم إرجاعه null . تم تعيين حالة userToken الأولية الخاصة بنا على null أيضًا.
  • نستخدم setUserToken لتعيين القيمة المرجعة من AsyncStorage باعتبارها userToken الجديد. إذا كانت القيمة التي تم إرجاعها null ، فهذا يعني أن userToken بنا يظل null .
  • بعد كتلة try{}…catch(){} ، قمنا بتعيين isLoading على false لأن وظيفة التحقق من حالة المصادقة قد اكتملت. سنحتاج إلى قيمة isLoading لمعرفة ما إذا كان لا يزال يتعين علينا عرض TransitionScreen أم لا. يجدر التفكير في تعيين خطأ إذا كان هناك خطأ في استرداد الرمز المميز حتى نتمكن من إظهار المستخدم زر "إعادة المحاولة" أو "المحاولة مرة أخرى" عند مواجهة الخطأ.
  • عندما AuthState ، نريد التحقق من حالة المصادقة ، لذلك نستخدم useEffect() ReactJS للقيام بذلك. نسمي الدالة checkAuthenticationStatus() داخل useEffect() قيمة isLoading على false عند الانتهاء.
  • أخيرًا ، نضيف حالاتنا إلى قيم <AuthContext.Provider/> الخاصة بنا حتى نتمكن من الوصول إليها من أي مكان في تطبيقنا المشمول بواجهة برمجة تطبيقات السياق.

الآن بعد أن أصبح لدينا وظيفتنا ، حان الوقت للعودة إلى AppNavigator.js وكتابة الكود الخاص بتركيب متصفح مكدس معين بناءً على حالة المصادقة:

التنقل> AppNavigator.js

أولاً ، سنستورد كل ما نحتاجه لـ AppNavigator.js .

 import React, { useEffect, useContext } from "react"; import PreAuthNavigator from "./preAuthNavigator"; import PostAuthNavigator from "./postAuthNavigator"; import { NavigationContainer } from "@react-navigation/native" import { createStackNavigator } from "@react-navigation/stack"; import AuthContext from "../../context/authContext/AuthContext"; import TransitionScreen from "../screens/TransitionScreen";

الآن بعد أن أصبح لدينا جميع وارداتنا ، فلنقم بإنشاء وظيفة AppNavigator() .

 ... const AppNavigator = () => { } export default AppNavigator

بعد ذلك ، سنمضي قدمًا في كتابة محتوى وظيفة AppNavigator() الخاصة بنا:

 import React, { useState, useEffect, useContext } from "react"; import PreAuthNavigator from "./preAuthNavigator"; import PostAuthNavigator from "./postAuthNavigator"; import { NavigationContainer } from "@react-navigation/native" import { createStackNavigator } from "@react-navigation/stack"; import AuthContext from "../../context/authContext/AuthContext"; import TransitionScreen from "../screens/transition"; const AppNavigator = () => { const { Navigator, Screen } = createStackNavigator(); const authContext = useContext(AuthContext); const { userToken, isLoading } = authContext; if(isLoading) { return <TransitionScreen /> } return ( <NavigationContainer> <Navigator> { userToken == null ? ( <Screen name="PreAuth" component={PreAuthNavigator} options={{ header: () => null }} /> ) : ( <Screen name="PostAuth" component={PostAuthNavigator} options={{ header: () => null }} /> ) } </Navigator> </NavigationContainer> ) } export default AppNavigator

في الجزء العلوي من الكود ، إليك مخطط لما فعلناه:

  • قمنا بإنشاء متصفح مكدس ودمرنا Navigator Screen منه.
  • لقد قمنا باستيراد userToken و isLoading من AuthContext بنا
  • عندما يتم AuthState ، يتم استدعاء checkAuthenticationStatus() في ربط useEffecct هناك. نستخدم عبارة if للتحقق مما إذا كان isLoading true ، وإذا كان true ، فإن الشاشة التي نعيدها هي <TransitionScreen /> التي أنشأناها مسبقًا لأن وظيفة checkAuthenticationStatus() لم تكتمل بعد.
  • بمجرد اكتمال checkAuthenticationStatus() الخاصة بنا ، يتم تعيين isLoading على false ونعيد مكونات التنقل الرئيسية الخاصة بنا.
  • تم استيراد NavigationContainer من @react-navigation/native . يتم استخدامه مرة واحدة فقط في متصفح المستوى الأعلى الرئيسي. لاحظ أننا لا نستخدم هذا في preAuthNavigator.js أو postAuthNavigator.js.
  • في AppNavigator() ، ما زلنا ننشئ متصفح مكدس. إذا كان userToken الذي تم الحصول عليه من واجهة برمجة تطبيقات السياق الخاصة بنا null ، فإننا نقوم بتركيب PreAuthNavigator ، إذا كانت قيمته شيئًا آخر (بمعنى أن AsyncStorage.getItem() في checkAuthenticationStatus() أعاد قيمة فعلية) ، فسنقوم بتركيب PostAuthNavigator . يتم إجراء التصيير الشرطي باستخدام عامل التشغيل الثلاثي.

الآن قمنا بإعداد AppNavigator.js الخاص بنا. بعد ذلك ، نحتاج إلى تمرير AppNavigator إلى ملف App.js الخاص بنا.

لنمرر AppNavigator الخاص بنا إلى ملف App.js :

App.js

 ... import AppNavigator from './views/navigation/AppNavigator'; ... return ( <AuthState> <AppNavigator /> </AuthState> );

دعنا الآن نرى كيف يبدو تطبيقنا في الوقت الحالي:

إليك ما يحدث عند تقديم بيانات اعتماد غير صحيحة أثناء محاولة تسجيل الدخول:

إضافة وظيفة تسجيل الخروج

في هذه المرحلة ، اكتملت عملية المصادقة واختيار المسار. الشيء الوحيد المتبقي لتطبيقنا هو إضافة وظيفة تسجيل الخروج.

زر تسجيل الخروج موجود في ملف HomeScreen.js . لقد مررنا وظيفة onLogout onLogout() إلى سمة onPress للزر. في الوقت الحالي ، لدينا عبارة console.log() البسيطة في وظيفتنا ، ولكن بعد قليل سيتغير ذلك.

الآن ، دعنا نذهب إلى AuthState.js الخاص بنا ونكتب وظيفة تسجيل الخروج. تعمل هذه الوظيفة على مسح AsyncStorage حيث يتم حفظ الرمز المميز للمستخدم.

السياق> authContext> AuthState.js

 ... const AuthState = (props) => { ... const userSignout = async() => { await AsyncStorage.removeItem('user-token'); setUserToken(null); } return ( ... ) } export default AuthState;

تعد userSignout() وظيفة غير متزامنة تزيل user-token من AsyncStorage .

نحتاج الآن إلى استدعاء وظيفة userSignout() في HomeScreen.js في أي وقت يتم فيه النقر فوق زر تسجيل الخروج.

دعنا ننتقل إلى HomeScreen.js الخاص بنا ونستخدم هناك userSignout() من AuthContext بنا.

الشاشات> postAuthScreens> HomeScreen.js

 import React, { useContext } from 'react'; import { View, Text, Button, StyleSheet } from 'react-native'; import AuthContext from '../../../context/authContext/AuthContext' const HomeScreen = () => { const { userSignout } = useContext(AuthContext) const onLogout = () => { userSignout() } return ( <View style={styles.container}> <Text>Now you're authenticated! Welcome!</Text> <Button title="LOG OUT" onPress={onLogout} /> </View> ) } ...

في كتلة التعليمات البرمجية أعلاه قمنا باستيراد خطاف useContext من ReactJS ، ثم قمنا باستيراد AuthContext الخاص بنا. بعد ذلك ، قمنا بتدمير وظيفة userSignout من AuthContext الخاصة بنا ويتم استدعاء وظيفة userSignout() onLogout() في وظيفة onLogout () الخاصة بنا.

الآن عندما يتم النقر فوق زر تسجيل الخروج الخاص بنا ، يتم مسح رمز المستخدم في AsyncStorage بنا.

هاهو! تم الانتهاء من العملية برمتها.

إليك ما يحدث عند الضغط على زر الرجوع بعد تسجيل الدخول:

الضغط على زر الرجوع بعد تسجيل الدخول إلى التطبيق.

إليك ما يحدث عند الضغط على زر الرجوع بعد تسجيل الخروج:

الضغط على زر الرجوع بعد تسجيل الخروج من التطبيق.

فيما يلي بعض السلوكيات المختلفة التي نلاحظها عند استخدام هذا النمط في تبديل حزمة التنقل الخاصة بنا:

  1. ستلاحظ أنه لم يكن هناك مكان نحتاج إليه للاستفادة من navigation.navigate() أو navigation.push() للانتقال إلى طريق آخر بعد تسجيل الدخول. بمجرد تحديث حالتنا برمز المستخدم ، يتم تغيير مكدس التنقل الذي تم تقديمه تلقائيًا.
  2. الضغط على زر الرجوع على جهازك بعد نجاح تسجيل الدخول لا يمكن أن يعيدك إلى صفحة تسجيل الدخول ، وبدلاً من ذلك ، فإنه يغلق التطبيق بالكامل. هذا السلوك مهم لأنك لا تريد أن يتمكن المستخدم من العودة إلى صفحة تسجيل الدخول إلا إذا قام بتسجيل الخروج من التطبيق. ينطبق الشيء نفسه على تسجيل الخروج - بمجرد تسجيل المستخدم للخروج ، لا يمكنه استخدام زر الرجوع للعودة إلى شاشة الشاشة HomeScreen ، ولكن بدلاً من ذلك ، يتم إغلاق التطبيق.

خاتمة

في العديد من التطبيقات ، تعد المصادقة أحد أهم الأجزاء لأنها تؤكد أن الشخص الذي يحاول الوصول إلى المحتوى المحمي له الحق في الوصول إلى المعلومات. يعد تعلم كيفية القيام بذلك بشكل صحيح خطوة مهمة في بناء تطبيق رائع وبديهي وسهل الاستخدام / التنقل.

بناءً على هذا الرمز ، إليك بعض الأشياء التي قد تفكر في إضافتها:

  • التحقق من صحة النموذج للتحقق من صحة حقول الإدخال. تحقق من التحقق من صحة النموذج الأصلي من React مع Formik و Yup.
  • مصادقة Firebase لدمج المصادقة مع Gmail أو Github أو Facebook أو Twitter أو واجهتك المخصصة. تحقق من React Native Firebase.
  • مفاهيم الكود للمصممين: المصادقة والترخيص.

إليك أيضًا بعض الموارد المهمة التي وجدتها والتي ستوضح لك المزيد حول المصادقة والأمان وكيفية القيام بذلك بشكل صحيح:

موارد

  • رد الفعل الأصلي: شرح تدفق مصادقة المستخدم
  • أفضل 10 ممارسات أمان في React
  • طرق المصادقة التي يمكن أن تمنع الخرق التالي
  • عرض بناء / معاينة مباشرة لتطبيقنا هنا ؛
  • اعرض المشروع على جيثب.