افزودن احراز هویت به اپلیکیشن ری اکت نیتیو — از صفر تا صد

۱۲ بازدید
آخرین به‌روزرسانی: ۱ شهریور ۱۳۹۹
زمان مطالعه: ۱۲ دقیقه

با استفاده از قلاب‌های ری‌اکت و React Context API به همراه Expo یا React Native CLI می‌توان هویت کاربران اپلیکیشن‌های ری‌اکت نیتیو را به روشی مدرن احراز کرد. به این ترتیب در این راهنما با روش افزودن احراز هویت به اپلیکیشن ری اکت نیتیو آشنا خواهیم شد به طوری که کاربران بتوانند کارهای زیر را انجام دهند:

  • ثبت نام (یک ایمیل تأیید هویت پس از ثبت نام ارسال می‌شود).
  • لاگین (کاربران می‌توانند در صورت تأیید کردن ایمیل خود وارد حسابشان شوند)
  • به‌روزرسانی پروفایل
  • بازیابی رمز عبور
افزودن احراز هویت به اپلیکیشن ری اکت نیتیو
ثبت نام
افزودن احراز هویت به اپلیکیشن ری اکت نیتیو
لاگین، نام کاربری و به‌روزرسانی پروفایل

برای پیگیری این راهنما به Authentication API نیاز دارید که می‌توانید با توجه به راهنمایی‌های این مطلب (+) ایجاد کرده و یا از دموی ارائه شده در این صفحه (+) استفاده کنید.

همچنین باید نرم‌افزارهای زیر را روی سیستم خود داشته باشید:

  • Expo (+)
  • ریپوی اولیه اپلیکیشن (+)
  • ریپوی نسخه React Native CLI (+)

بخش اول: راه‌اندازی پروژه، وابستگی و ساختار فایل

در این بخش به توضیح مراحل تنظیمات اولیه پروژه، نصب وابستگی‌ها و سازماندهی فایل‌ها و پوشه‌ها می‌پردازیم.

گام 1: ایجاد پروژه

برای ایجاد پروژه باید دستور زیر را اجرا کنید. یک قالب خالی را انتخاب کنید و نام اپلیکیشن خود را تعیین نمایید:

Expo

$ expo init react-native-authentication
$ cd react-native-authentication

React Native CLI

$ npx react-native init ReactNativeAuthentication
$ cd ReactNativeAuthentication

گام 2: نصب وابستگی‌ها

ما از پکیج‌های زیر استفاده خواهیم کرد.

  • Axios (+) – یک کلاینت HTTP مبتنی بر Promise برای ایجاد فراخوانی‌ها به API است.
  • فرم ابتدایی ری‌اکت نیتیو (+).
$ npm i --save axios react-native-basic-form react-native-elements

وابستگی‌های ناوبری نیز به شرح زیر هستند:

  • React Navigation (+) – برای ناوبری درون اپلیکیشن استفاده می‌شود.
  • React Navigation Stack (+)- ناوبری استک است که روی سیستم‌های عامل اندروید و iOS استفاده می‌شود.
$ npm i --save react-navigation react-navigation-stack
  • Expo
$ expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
  • React Native CLI
$ npm install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view --save
  • لینک کردن کتابخانه‌ها
$ cd ios; pod install; cd..
  • آیکون‌های بُرداری
npm i --save react-native-vector-icons

react-native link react-native-vector-icons

گام 3: ایجاد ساختار پوشه

در ریشه پروژه، پوشه‌ای به نام app ایجاد کنید. درون این پوشه، ‌پوشه‌های زیر را ایجاد کنید:

  • Components – شامل همه کامپوننت‌ها خواهد بود.
  • Scenes – شامل همه صحنه‌ها خواهد بود.
  • Routes – مسیرهای اپلیکیشن را شامل می‌شود.
  • Services – شامل کارکردهایی برای دسترسی به API بک‌اند خواهد بود.

مطمئن شوید که در ریشه پروژه هستید و دستورهای زیر را اجرا کنید:

$ mkdir app && cd app

$ mkdir providers services components scenes routes

بخش دوم

در این بخش به بررسی ثابت‌ها، ارائه‌دهنده، ردیوسر و سرویس‌ها می‌پردازیم.

گام 4: پیکربندی

در پوشه app دو فایل به نام‌های constants.js و theme.js ایجاد می‌کنیم. فایل constants.js شامل url API، نقاط انتهایی آن و دیگر متغیرهای پیکربندی اعلان شده خواهد بود:

  • فایل constants.js
import React from 'react';

//API URL
export const API_URL = 'https://mesannodejsapiwithverification.herokuapp.com/api';

//API End Points
export const REGISTER = `${API_URL}/auth/register`;
export const LOGIN = `${API_URL}/auth/login`;
export const UPDATE_PROFILE = `${API_URL}/user`;
export const UPLOAD_IMAGE = `${API_URL}/user/upload`;
export const FORGOT_PASSWORD = `${API_URL}/auth/recover`;
  • فایل theme.js
import {Platform} from "react-native";

export let font = Platform.OS === 'ios' ? 'HelveticaNeue' : 'Roboto';
export let titleColor = '#363434';

//Nav Shared Styles
export let headerStyle = {backgroundColor: '#fff', borderBottomWidth:0, shadowColor: 'transparent'};
export let headerTitleStyle = {fontWeight: 'bold', fontSize: 17, fontFamily: font, color: titleColor};

export const imageOptions = {allowsEditing: true, aspect: [4, 3]};

گام 5: ارائه‌دهنده

در پوشه providers یک فایل به نام auth.js و با محتوای زیر ایجاد کنید:

  • فایل auth.js
import React, {useMemo, useReducer, useContext} from 'react';
import {AsyncStorage} from "react-native";
import axios from "axios";

//IMPORT REDUCER, INITIAL STATE AND ACTION TYPES
import reducer, {initialState, LOGGED_IN, LOGGED_OUT} from "./reducer";

// CONFIG KEYS [Storage Keys]===================================
export const TOKEN_KEY = 'token';
export const USER_KEY = 'user';
export const keys = [TOKEN_KEY, USER_KEY];

// CONTEXT ===================================
const AuthContext = React.createContext();

function AuthProvider(props) {
    const [state, dispatch] = useReducer(reducer, initialState || {});

    // Get Auth state
    const getAuthState = async () => {
        try {
            //GET TOKEN && USER
            let token = await AsyncStorage.getItem(TOKEN_KEY);
            let user = await AsyncStorage.getItem(USER_KEY);
            user = JSON.parse(user);
            
            if (token !== null && user!== null) await handleLogin({token, user});
            else await handleLogout();

            return {token, user};
        } catch (error) {
            throw new Error(error)
        }
    };

    // Handle Login
    const handleLogin = async (data) => {
        try{
            //STORE DATA
            let {token, user} = data;
            let data_ = [[USER_KEY, JSON.stringify(user)], [TOKEN_KEY, token]];
            await AsyncStorage.multiSet(data_);

            //AXIOS AUTHORIZATION HEADER
            axios.defaults.headers.common["Authorization"] = `Bearer ${data.token}`;

            //DISPATCH TO REDUCER
            dispatch({type: LOGGED_IN, user:data.user});
        }catch (error) {
            throw new Error(error);
        }
    };

    // Handle Logout
    const handleLogout = async () => {
        try{

            //REMOVE DATA
            await AsyncStorage.multiRemove(keys);

            //AXIOS AUTHORIZATION HEADER
            delete axios.defaults.headers.common["Authorization"];

            //DISPATCH TO REDUCER
            dispatch({type: LOGGED_OUT});
        }catch (error) {
            throw new Error(error);
        }
    };

    //UPDATE USER LOCAL STORAGE DATA AND DISPATCH TO REDUCER
    const updateUser = async (user) => {
        try {
            await AsyncStorage.setItem(USER_KEY, JSON.stringify(user));
            dispatch({type: LOGGED_IN, user}); //DISPATCH TO REDUCER
        } catch (error) {
            throw new Error(error);
        }
    };

    const value = useMemo(() => {
        return {state, getAuthState, handleLogin, handleLogout, updateUser};
    }, [state]);

    return (
        <AuthContext.Provider value={value}>
            {props.children}
        </AuthContext.Provider>
    );
}

const useAuth = () => useContext(AuthContext);
export { AuthContext, useAuth }
export default AuthProvider;

در ابتدای فایل، context ایجاد شده است. reducer و initial state از فایل ردیوسری که در ادامه ایجاد خواهد شد ایمپورت می‌شوند و به قلابی به نام useReducer ارسال می‌شوند که حالت جاری را به همراه متد دیسپچ مشابه ریداکس بازگشت می‌دهد.

در ادامه تابع‌های مختلفی اعلان یافته و به صورت مقدار به provider ارسال شده‌اند. تابع getAuthState داده‌های کاربر را در صورت لاگین کردن بازگشت می‌دهد. تابع handleLogin توکن و داده‌های کاربران را ذخیره کرده، هدر Axios Authorization را تنظیم نموده و داده‌های کاربر را به ردیوسر هدایت می‌کند تا ذخیره شوند. تابع handleLogout دقیقاً کاری مخالف تابع قبلی انجام می‌دهد. تابع updateUser داده‌های کاربران را در فضای لوکال ذخیره کرده و داده‌های جدید را به ردیوسر ارسال می‌کند تا ذخیره شوند.

در انتهای فایل فوق یک شیء جدید useAuth با استفاده از قلابی به نام useContext که قبلاً در AuthContext اعلان کردیم، ایجاد شده است. این شیء مقدار context کنونی را برای context ما بیان می‌کند و همراه با AuthContext و Provider اکسپورت می‌شود.

گام 6: ردیوسر

در پوشه app فایلی به نام reducer.js ایجاد کنید. این ردیوسر مسئول به‌روزرسانی حالت اپلیکیشن بر مبنای اکشن ارسالی است.

//Action Types
export const LOGGED_IN = `auth/LOGGED_IN`;
export const LOGGED_OUT = `auth/LOGGED_OUT`;

export const  initialState = {
    isLoggedIn: false,
    user: null
};

//REDUCER
const authReducer = (state = initialState, action) => {
    switch (action.type) {
        case LOGGED_IN:{
            let { user } = action;

            return {...state, isLoggedIn: true, user};
        }

        case LOGGED_OUT:{
            return {...state, ...initialState};
        }

        default:
            return state;
    }
};

export default authReducer;

گام 7: سرویس‌ها

در پوشه services فایلی جدید به نام auth.js ایجاد کنید. این فایل شامل همه تابع‌هایی خواهد بود که برای دسترسی به نقاط انتهایی Authentication API مورد نیاز هستند:

  • فایل auth.js
import axios from 'axios';

import * as c from '../constants';

export async function register(data){
    try{
        let res = await axios.post(c.REGISTER, data);

        return res.data;
    }catch (e) {
        throw handler(e)
    }
}

export async function login(data){
    try{
        let res = await axios.post(c.LOGIN, data);

        return res.data;
    }catch (e) {
        throw handler(e);
    }
}

export async function forgotPassword(data) {
    try {
        let res = await axios.post(c.FORGOT_PASSWORD, data);

        return res.data;
    } catch (e) {
        throw handler(e);
    }
}

export async function updateProfile(userId, data){
    try{
        const options = {
            headers: {
                Accept: "application/json",
                "Content-Type": "multipart/form-data"
            }
        };

        const form_data = new FormData();
        for ( let key in data )
            form_data.append(key, data[key]);

        let res = await axios.put(`${c.UPDATE_PROFILE}/${userId}`, form_data, options);
        return res.data;
    }catch (e) {
        throw handler(e);
    }
}

export function handler(err) {
    let error = err;

    if (err.response && err.response.data.hasOwnProperty("message"))
        error = err.response.data;
    else if (!err.hasOwnProperty("message")) error = err.toJSON();

    return new Error(error.message);
}

در کد فوق تابع register درخواست API برای ثبت نام کاربر را ارائه می‌کند و پارامتر آن داده‌های کاربر است. تابع login درخواست ورود کاربر را عرضه می‌کند و پارامتر آن داده‌های کاربران است. تابع forgotPassword یک درخواست API برای ورود کاربر ایجاد می‌کند و پارامتر آن email در یک شیء است. تابع updateProfile یک درخواست API برای به‌روزرسانی داده‌ای کاربر ایجاد می‌کند و پارامترهای آن userId و data است. این تابع روی همه داده‌های ارسالی چرخش کرده و یک شیء به نام FormData می‌سازد. یک شیء axios options با نوع محتوا به صورت multipart/form-data نیز ایجاد می‌شود تا امکان آپلود تصویر وجود داشته باشد.

بخش سوم

در این بخش کامپوننت‌ها، صحنه‌ها و مسیرها را تنظیم خواهیم کرد.

گام 8: کامپوننت‌ها

در پوشه components فایلی به نام CTA.js با محتوای زیر ایجاد کنید:

import React from 'react';
import {View, Text, TouchableOpacity, StyleSheet} from 'react-native';

export default function CTA({title, ctaText, onPress, style, titleStyle, ctaStyle}){
    return (
        <View style={[styles.footer, style]}>
            {
                title &&
                <Text style={[styles.footerText, titleStyle, ctaText && {marginRight: 5}]}>
                    {title}
                </Text>
            }

            {
                ctaText &&
                <TouchableOpacity onPress={onPress}>
                    <Text style={[styles.footerCTA, ctaStyle]}>
                        {ctaText}
                    </Text>
                </TouchableOpacity>
            }
        </View>
    )
};

CTA.defaultProps = {
    title: null,
    ctaText: null,
    onPress:{},
    style: {},
    titleStyle: {},
    ctaStyle: {},
};

const styles = StyleSheet.create({
    footer: {
        flexDirection: "row",
        justifyContent: "center",
        alignItems: "center",
    },

    footerText: {
        fontSize: 16,
        fontFamily: "Helvetica Neue",
        color: "#636466"
    },

    footerCTA: {
        fontSize: 16,
        color: "#733AC2",
        fontWeight: "500",
        fontFamily: "Helvetica Neue"
    }
});

همچنین در همین پوشه فایلی به نام shared.js با محتوای زیر ایجاد می‌کنیم:

import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {Icon, Badge} from 'react-native-elements';

//HEADER COMPONENT
export const Header = (props) => {
    let {title, style} = props;

    return (
        <View style={[styles.header, style]}>
            <Text style={styles.headerText}>
                {title}
            </Text>
        </View>
    )
};

Header.defaultProps = {
    title: "",
    style: {}
};

//ERROR COMPONENT
export const ErrorText = ({error}) => {
    return <Text style={styles.errorText}>{error}</Text>
};

ErrorText.defaultProps = {
    error: ""
};

const styles = StyleSheet.create({
    header: {
        height: 50,
        justifyContent: "center"
    },

    headerText: {
        fontSize: 25,
        color: "#362068",
        fontWeight: "400",
        fontFamily: "Helvetica Neue"
    },

    errorText:{
        marginBottom: 8,
        color:"red"
    }
});

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

گام 9: صحنه‌ها

در پوشه scenes دو پوشه به نام‌های auth و home ایجاد می‌کنیم. در پوشه auth فایل‌های زیر را ایجاد خواهیم کرد.

  • فایل AuthLoading.js
import React, {useEffect} from 'react';
import {ActivityIndicator, View, Text} from 'react-native';
import { StackActions } from 'react-navigation';

import { useAuth } from "../../providers/auth";

export default function AuthLoading(props) {
    const {navigate} = props.navigation;
    const { getAuthState } = useAuth();

    useEffect(() => {
        initialize()
    }, []);

    async function initialize() {
        try {
            const {user} = await getAuthState();

            if (user) {
                //check if username exist
                let username = !!(user.username);

                if (username) navigate('App');
                else navigate('Auth', {}, StackActions.replace({ routeName: "Username" }))

            } else navigate('Auth');
        } catch (e) {
            navigate('Auth');
        }
    }

    return (
        <View style={{backgroundColor: "#fff", alignItems: 'center', justifyContent: 'center', flex: 1}}>
            <ActivityIndicator/>
            <Text>{"Loading User Data"}</Text>
        </View>
    );
};

این فایل در زمانی که اپلیکیشن بررسی می‌کند آیا کاربری وارد شده یا نه نمایش می‌یابد. در این کد از شیء useAuth برای بازیابی تابع getAuthState استفاده شده است. اگر کاربر موجود باشد، بررسی می‌کند آیا username تعیین شده یا نه و اگر چنین باشد به صحنه Home می‌رود، در غیر این صورت به صحنه Username خواهد رفت.

  • فایل Register.js
import React, { useState } from 'react';
import {Alert, View} from 'react-native';

import * as api from "../../services/auth";

import Form from 'react-native-basic-form';
import CTA from "../../components/CTA";
import {Header, ErrorText} from "../../components/Shared";

export default function Register(props) {
    const {navigation} = props;

    //1 - DECLARE VARIABLES
    const [error, setError] = useState(null);
    const [loading, setLoading] = useState(false);

    const fields = [
        {name: 'firstName', label: 'First Name', required: true},
        {name: 'lastName', label: 'Last Name', required: true},
        {name: 'email', label: 'Email Address', required: true},
        {name: 'password', label: 'Password', required: true, secure:true}
    ];

    async function onSubmit(state) {
        setLoading(true);

        try {
            let response = await api.register(state);
            setLoading(false);
            Alert.alert(
                'Registration Successful',
                response.message,
                [{text: 'OK', onPress: () => navigation.replace("Login")}],
                {cancelable: false},
            );
        } catch (error) {
            setError(error.message);
            setLoading(false)
        }
    }

    let formProps = {title: "Register", fields, onSubmit, loading };
    return (
        <View style={{flex: 1, paddingHorizontal: 16, backgroundColor:"#fff"}}>
            <Header title={"Register"}/>
            <View style={{flex:1}}>
                <ErrorText error={error}/>
                <Form {...formProps}>
                    <CTA
                        title={"Already have an account?"}
                        ctaText={"Login"}
                        onPress={() => navigation.replace("Login")}
                        style={{marginTop: 50}}/>
                </Form>
            </View>
        </View>
    );
};

Register.navigationOptions = ({}) => {
    return {
        title: ``
    }
};

صحنه Register تابع register سرویس auth را برای ثبت نام کاربر جدید فرا می‌خواند. در صورت موفقیت اپلیکیشن صحنه جاری را با صحنه Login عوض می‌کند. به این منظور از کامپوننت CTA استفاده می‌شود.

  • فایل Login.js
import React, { useState } from 'react';
import {View} from 'react-native';

import * as api from "../../services/auth";
import { useAuth } from "../../providers/auth";

import Form from 'react-native-basic-form';
import CTA from "../../components/CTA";
import {Header, ErrorText} from "../../components/Shared";

export default function Login(props) {
    const {navigation} = props;
    const {navigate} = navigation;

    //1 - DECLARE VARIABLES
    const [error, setError] = useState(null);
    const [loading, setLoading] = useState(false);
    const { handleLogin } = useAuth();

    const fields = [
        {name: 'email', label: 'Email Address', required: true},
        {name: 'password', label: 'Password', required: true, secure: true}
    ];

    async function onSubmit(state) {
        setLoading(true);

        try {
            let response = await api.login(state);
            await handleLogin(response);

            setLoading(false);

            //check if username is null
            let username = (response.user.username !== null);
            if (username) navigate('App');
            else navigation.replace('Username');
        } catch (error) {
            setError(error.message);
            setLoading(false)
        }
    }

    let formProps = {title: "Login", fields, onSubmit, loading};
    return (
        <View style={{flex: 1, paddingHorizontal: 16, backgroundColor:"#fff"}}>
            <Header title={"Login"}/>
            <View style={{flex: 1}}>
                <ErrorText error={error}/>
                <Form {...formProps}>
                    <CTA
                        ctaText={"Forgot Password?"}
                        onPress={() => navigation.navigate("ForgotPassword")}
                        style={{marginTop: 20}}/>

                    <CTA
                        title={"Don't have an account?"}
                        ctaText={"Register"}
                        onPress={() => navigation.replace("Register")}
                        style={{marginTop: 50}}/>
                </Form>
            </View>
        </View>
    );
};

Login.navigationOptions = ({}) => {
    return {
        title: ``
    }
};

صحنه Login تابع updateProfile سرویس auth را برای وارد کردن فرد به حساب کاربری خود فرا می‌خواند. در صورت موفقیت به صفحه Home می‌رود. از کامپوننت CTA استفاده می‌کند.

  • فایل Username.js
import React, { useState } from 'react';
import {View} from 'react-native';

import * as api from "../../services/auth";
import { useAuth } from "../../providers/auth";

import Form from 'react-native-basic-form';
import {Header, ErrorText} from "../../components/Shared";

export default function Username (props) {
    const {navigation} = props;

    //1 - DECLARE VARIABLES
    const [error, setError] = useState(null);
    const [loading, setLoading] = useState(false);
    const { state, updateUser } = useAuth();

    const fields = [
        {name: 'username', label: 'Username', required: true}
    ];

    async function onSubmit(data) {
        setLoading(true);

        try {
            let response = await api.updateProfile(state.user._id, data);
            updateUser(response.user);

            setLoading(false);

            navigation.navigate('App');
        } catch (error) {
            setError(error.message);
            setLoading(false)
        }
    }

    let formProps = {title: "Submit", fields, onSubmit, loading };
    return (
        <View style={{flex: 1, paddingHorizontal: 16, backgroundColor:"#fff"}}>
            <Header title={"Select Username"}/>
            <View style={{flex:1}}>
                <ErrorText error={error}/>
                <Form {...formProps}/>
            </View>
        </View>
    );
};

Username.navigationOptions = ({}) => {
    return {
        title: ``
    }
};

صحنه Username برای به‌روزرسانی داده‌های کاربران از تابع updateProfile سرویس auth استفاده می‌کند. در صورت موفقیت به صفحه Home می‌رود.

  • فایل ForgotPassword.js
import React, { useState } from 'react';
import {Alert, View} from 'react-native';

import * as api from "../../services/auth";

import Form from 'react-native-basic-form';
import {Header, ErrorText} from "../../components/Shared";

export default function ForgotPassword(props) {
    const {navigation} = props;

    //1 - DECLARE VARIABLES
    const [error, setError] = useState(null);
    const [loading, setLoading] = useState(false);

    const fields = [{name: 'email', label: 'Email Address', required: true}];

    async function onSubmit(state) {
        setLoading(true);

        try {
            let response = await api.forgotPassword(state);
            setLoading(false);

            Alert.alert(
                'Recover Password',
                response.message,
                [{text: 'OK', onPress: () => navigation.goBack()}],
                {cancelable: false},
            );
        } catch (error) {
            setError(error.message);
            setLoading(false)
        }
    }

    let formProps = {title: "Submit", fields, onSubmit, loading };
    return (
        <View style={{flex: 1, paddingHorizontal: 16, backgroundColor:"#fff"}}>
            <Header title={"Recover Password"}/>
            <View style={{flex:1}}>
                <ErrorText error={error}/>
                <Form {...formProps}/>
            </View>
        </View>
    );
};

ForgotPassword.navigationOptions = ({}) => {
    return {
        title: ``
    }
};

صحنه Forgot Password تابع forgotPassword سرویس auth را برای به‌روزرسانی داده‌های کاربران فرا می‌خواند. در صورت موفقیت به صفحه Login بازمی‌گردد. در ادامه در پوشه home دو فایل به نام‌های Home.js و UpdateProfile.js ایجاد می‌کنیم.

  • فایل Home.js
import React, {useState, useContext} from 'react';
import {Text, View, Button, ActivityIndicator, Alert} from 'react-native';

import { useAuth } from "../../providers/auth";

export default function Home(props) {
    const {navigate} = props.navigation;

    const {state, handleLogout} = useAuth();
    const user = state.user;

    return (
        <View style={{flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center'}}>
            <Text>{`Welcome ${user.firstName} ${user.lastName} (${user.username})`}</Text>

            <Button title={"Update Profile"} onPress={() => navigate('UpdateProfile')}/>

            <Button title={"Log Out"} onPress={() => {
                handleLogout();
                navigate('Auth');
            }}/>
        </View>
    );
}

این فایل صفحه‌ای با پیام خوشامدگویی و دکمه‌های Logout و Update Profile نمایش می‌دهد و از شیء useAuth برای بازیابی داده‌های کاربران و تابع استفاده می‌کند.

  • فایل UpdateProfile.js
import React, { useState } from 'react';
import {View} from 'react-native';

import * as api from "../../services/auth";
import { useAuth } from "../../providers/auth";

import Form from 'react-native-basic-form';
import {ErrorText} from "../../components/Shared";

export default function UpdateProfile (props) {
    const {navigation} = props;

    //1 - DECLARE VARIABLES
    const [error, setError] = useState(null);
    const [loading, setLoading] = useState(false);
    const { state, updateUser } = useAuth();

    const fields = [
        {name: 'firstName', label: 'First Name', required: true},
        {name: 'lastName', label: 'Last Name', required: true},
        {name: 'username', label: 'Username', required: true}
    ];

    async function onSubmit(data) {
        setLoading(true);

        try {
            let response = await api.updateProfile(state.user._id, data);
            updateUser(response.user);

            setLoading(false);

            navigation.goBack();
        } catch (error) {
            setError(error.message);
            setLoading(false)
        }
    }

    return (
        <View style={{flex: 1, paddingHorizontal: 16, backgroundColor:"#fff"}}>
            <View style={{flex:1}}>
                <ErrorText error={error}/>
                <Form
                    fields={fields}
                    title={'Submit'}
                    loading={loading}
                    initialData={state.user}
                    error={error}
                    onSubmit={onSubmit}/>
            </View>
        </View>
    );
};

UpdateProfile.navigationOptions = ({}) => {
    return {
        title: `Update Profile`
    }
};

این فایل تابع updateProfile سرویس auth را فرا می‌خواند تا داده‌های کاربران را به‌روزرسانی کند. در صورت موفقیت اپلیکیشن به صحنه Home بازمی‌گردد.

گام 10: مسیرها

در پوشه routes دو فایل به نام‌های auth.js و home.js ایجاد می‌کنیم. در این فایل‌ها، تابع createStackNavigator مربوط به React Navigation برای ایجاد رشته مسیرها مورد استفاده قرار می‌گیرد. پشته مسیرهای احراز هویت شامل صحنه‌های Register، Login، Username و ForgotPassword است.

  • فایل auth.js
import React from 'react';
import {createStackNavigator} from 'react-navigation-stack';

//IMPORT SCENES
import RegisterScreen from "../scenes/auth/Register";
import LoginScreen from "../scenes/auth/Login";
import UsernameScreen from "../scenes/auth/Username";
import ForgotPasswordScreen from "../scenes/auth/ForgotPassword";

import {headerStyle, headerTitleStyle} from '../theme'

//Create Routes
const AuthStack = createStackNavigator(
    {
        Register: RegisterScreen,
        Login: LoginScreen,
        Username: UsernameScreen,
        ForgotPassword: ForgotPasswordScreen
    },
    {
        initialRouteName: 'Login',
        defaultNavigationOptions: () => ({headerStyle, headerTitleStyle})
    }
);

export default AuthStack;
  • فایل home.js
import React from 'react';
import {createStackNavigator} from 'react-navigation-stack';

//IMPORT SCENES
import HomeScreen from "../scenes/home/Home";
import UpdateProfileScreen from "../scenes/home/UpdateProfile";

import {headerStyle, headerTitleStyle} from '../theme'

const HomeStack = createStackNavigator(
    {
        Home: HomeScreen,
        UpdateProfile: UpdateProfileScreen,
    },
    {
        initialRouteName: 'Home',
        defaultNavigationOptions: () => ({headerStyle, headerTitleStyle})
    }
);

export default HomeStack;

بخش چهارم

در این بخش به جمع‌بندی همه مباحث مطرح‌شده می‌پردازیم.

روتر

در پوشه app یک فایل به نام router.js و با محتوای زیر ایجاد می‌کنیم:

import React from 'react';

import {createAppContainer, createSwitchNavigator} from 'react-navigation';

//IMPORT ROUTES
import AuthStack from "./routes/auth";
import HomeStack from "./routes/home";

import AuthLoading from "./scenes/auth/AuthLoading";
import AuthProvider from "./providers/auth";

//APP ROUTES STACK
const AppStack = createSwitchNavigator(
    {
        Loading: AuthLoading,
        Auth: AuthStack,
        App: HomeStack
    },
    {initialRouteName: 'Loading'}
);

const Navigator = createAppContainer(AppStack);

export default function Router(props) {
    return (
        <AuthProvider>
            <Navigator/>
        </AuthProvider>
    );
}

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

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

// * Description: App Entry Point
import React, {Component} from 'react';

import Router from './app/router'

export default class App extends Component {
    render() {
        return <Router/>;
    }
}

در فایل فوق روتر ایمپورت شده است.

گام 11: تست

برای تست اپلیکیشن دستور زیر را اجرا کنید:

Expo
$ expo start
React Native CLI
$ npx react-native run-ios

بدین ترتیب به پایان این راهنما می‌رسیم.

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

==

بر اساس رای ۱ نفر
آیا این مطلب برای شما مفید بود؟
شما قبلا رای داده‌اید!
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
better-programming
۲ thoughts on “افزودن احراز هویت به اپلیکیشن ری اکت نیتیو — از صفر تا صد

سلام
ممنون مطلب خوبی بود …
فقط اینکه بنظر میرسه فایل auth.js که در provider قرار داره ، ناقصه چونکه با توضیحاتی که زیرش نوشتین مطابقت نداره.

سلام دوست عزیز؛
موردی که فرمودید بررسی شد. بخشی از کد به درستی درج نشده بود که اصلاح شد.
از توجه و دقت نظر شما سپاسگزاریم.

نظر شما چیست؟

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