Create chat app using react-native and Firebase

بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته

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

خلونا نبدآ اولا بآنشاء التطبيق وليكم هنسمية chatApp

npx react-native init chatApp

بعد انشاء التطبيق هنضيف بعض الـ Dependencies المهمة والي هتساعدنا في التطبيق

اولا هنضيف باكيدج React Navigation V5 للتطبيق علشان نقدر نتنقل بين الشاشات بسهوله. ممكن تشوفوا طريقة اضافتها من الفيديو دا

ثانيا هنضيف باكيدج React Native firebase علشان نضيف جزء تسجيل الدخول والتسجيل وكمان علشان نستخدم ال Real-time database الي هنخزن فيها رسايل الدردشة.علشان تضيف الباكيدج شوف الفيديو دا بيشرح طريقة الاضافة:

ثالثا هنضيف باكيدج React-native Gifted Chat ودي هتساعدنا في تصميم شاشة الدردشة بدون ما نعملها Custom وهتوفر علينا كتير. ولاضافتها فقط استخدم YARN كالتالي:

yarn add react-native-gifted-chat

كده احنا خلصنا اضافة الـ Dependencies الي محتاجينها علشان نشتغل في التطبيق ولو شوفنا الفيديو الي في الخطوة رقم 2 يبقي عملنا بروجكت جديد علي Firebase Console وربطناه بالبروجكت بتاعنا.

نيجي لاول شاشة في التطبيق وهي App.js . خلونا نحذف محتواها خالص ونبدآ نكتب من اول وجديد

هنستخدم فيها ال React navigation مع ال Firebase Auth علشان نشوف الي بيفتح التطبيق عضو ولا زائر ولو كان زائر هنخلية يروح علي صفحة التسجيل/الدخول ولو عضو هننقلة لصفحة الدردشة.

محتوي صفحة App.js

import React, {useState, useEffect} from 'react';
import {Text, Button} from 'react-native';
import auth from '@react-native-firebase/auth';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import Chat from './Chat';
import Login from './Login';

export default function App() {
    // Set an initializing state whilst Firebase connects
    const [initializing, setInitializing] = useState(true);
    const [user, setUser] = useState();

    // Handle user state changes
    function onAuthStateChanged(user) {
        setUser(user);
        if (initializing) setInitializing(false);
    }

    useEffect(() => {
        const subscriber = auth().onAuthStateChanged(onAuthStateChanged);
        return subscriber; // unsubscribe on unmount
    }, []);

    const Stack = createStackNavigator();


    if (initializing) return null;

    if (!user) {
        return (
            <NavigationContainer>
                <Stack.Navigator>
                    <Stack.Screen name="Home" component={Login}/>
                </Stack.Navigator>
            </NavigationContainer>
        );

    }

    return (
        <NavigationContainer>
            <Stack.Navigator>
                <Stack.Screen name="Home" component={Chat} options={({navigation, route}) => ({

                    headerRight: props => <Button title="signout" onPress={() => auth().signOut()}/>

                })}/>
            </Stack.Navigator>
        </NavigationContainer>
    );

}

لو ركزنا في الكود المكتوب فوق هنلاحظ انه فانكشن ال App كلها هي نفس ال Sample الي اخدتة من ال Firebase auth بس ال Return بتاعها غيرته شوية ودخلت معاه ال Navigation بحيث ترجع لليوزر في حالة انه عمل تسجيل دخول Stack الشات وفي حالة انه لسه مش عامل تسجيل دخول ترجعله stack فيه شاشه اللوجن.
وممكن نضيف في نفس الستاك دا اي شاشات تانيه عاوزينها تظهر لليوزر لو مش عامل لوجن زي برده ال Register او غيرها.

طبعا لو جينا نعمل Run للكود دا هيدينا ايرور لان الصفحات المكتوبه في الكود وعاملين ليها Import لسه لم يتم انشائها فخلونا ننشئ الصفحات دي سريعا ونكتب اي Test code مؤقتا لحد ما نرجعلها.

هنعمل فايل جديد اسمه Chat.js ونكتب فيه الكود دا

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

export default function Chat() {
return (
<Text>Chat Screen</Text>
);
}

ونعمل فايل تاني اسمة Login.js ونكتب فيه الكود دا

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

 export default function Login() {
 return (
 <Text>Login Screen</Text>
 );
 }

نحفظ الصفحتين ونعمل Build للتطبيق تاني ونتآكد انه بيشتغل تمام بدون اخطاء وانه بيودي لصفحة ال Login لان اليوزر مش عامل Login لحد دلوقتي.

لو في اي ايرور اكتبولي في التعليقات.

لو الامور كلها تمام نكمل ونبدآ شغل في صفحة اللوجن ونبدآ نبني فورمة اللوجن.

ال JSX بتاعنا هيبقي شكلة كده

        <View>
            <Text style={{textAlign: 'center', paddingVertical: 20}}>Please login</Text>
            <View style={{padding: 10}}>
                <TextInput
                    style={{height: 40, borderColor: 'gray', borderWidth: 1}}
                    onChangeText={text => setEmail(text)}
                    value={email}

                />
                <TextInput
                    style={{height: 40, borderColor: 'gray', borderWidth: 1}}
                    onChangeText={text => setPassword(text)}
                    value={password}
                    secureTextEntry={true}
                />

                <Button
                    title="Login"
                    onPress={() => {
                        doLogin(email, password)
                    }}
                />
            </View>
        </View>

دا عبارة عن اتنين Text input واحد منهم للايميل وواحد للباسورد. و Button اليوزر يضغط عليه يعمل تسجيل دخول.

وبما اننا عاملين Text input لازم يبقي عندنا State علشان ناخد الداتا الي هيدخلها اليوزر وبما اننا بنستخدم Function component فلازم نستخدم Hooks علشان نقدر نستخدم ال State لان زي ماحنا عارفين ال Function Component مقدرش استخدم فيها ال State زي ال Class component.

لازم نعمل import لل useState function الاول وبالتالي شكل ال Import الخاص بال React هيبقي كده
import React, {useState} from 'react';

كمان لازم نعرف ال State فوق في بداية ال Function فهنكتب كده

    const [email, setEmail] = React.useState('hosam.zewain@gmail.com');
    const [password, setPassword] = React.useState('123456');


محتاجين بقي نكمل ال Action الي هيحصل لما اليوزر يضغط علي login وينادي علي الفانكشن الي اسمها doLogin() المكتوبة في onPress. فخلونا نكتب ال Function الي هيكون شكلها كده:

function doLogin(email, password) {
    auth().signInWithEmailAndPassword(email, password)
        .catch(error => {
            auth().createUserWithEmailAndPassword(email, password)
                .then(() => {
                    alert('account created')
                }).catch(error => {
                console.error(error);
            });
        });
}


لو قرآنا ال Function الي فوق دي هنلاقيها بتاخد ال Email وال Password الي اليوزر دخلهم وبتحاول تعمل تسجيل دخول ولو لقيت الميل مش موجود هتعمل تسجيل جديد بالميل والباسورد الي دخل. طبعا دا مش افضل حاجه بس احنا بنحاول نختصر شويه بدل ما نعمل فورمة تانية للتسجيل.

كده شكل صفحة ال login كلها علي بعضها هتكون كده:

/**
 * Created by HosamMacBook on 1/21/21.
 */
import React, {useState} from 'react';
import {View, Text, TextInput, Button} from 'react-native';
import auth from '@react-native-firebase/auth';


export default function Login() {
    const [email, setEmail] = React.useState('hosam.zewain@gmail.com');
    const [password, setPassword] = React.useState('123456');

    return (
        <View>
            <Text style={{textAlign: 'center', paddingVertical: 20}}>Please login</Text>
            <View style={{padding: 10}}>
                <TextInput
                    style={{height: 40, borderColor: 'gray', borderWidth: 1}}
                    onChangeText={text => setEmail(text)}
                    value={email}

                />
                <TextInput
                    style={{height: 40, borderColor: 'gray', borderWidth: 1}}
                    onChangeText={text => setPassword(text)}
                    value={password}
                    secureTextEntry={true}
                />

                <Button
                    title="Login"
                    onPress={() => {
                        doLogin(email, password)
                    }}
                />
            </View>
        </View>
    );
}

function doLogin(email, password) {
    auth().signInWithEmailAndPassword(email, password)
        .catch(error => {
            auth().createUserWithEmailAndPassword(email, password)
                .then(() => {
                    alert('account created')
                }).catch(error => {
                console.error(error);
            });
        });
}

كده خلصنا صفحة ال login ونيجي بقي لصفحة ال Chat وقبل ما نعمل اي حاجه هنحتاج ننزل مكتبة ال Realtime database الخاصة بالفايربيز

ببساطة شديدة في فولدر البروجكت اكتب في الترمنال

yarn add @react-native-firebase/database

ولازم قبل ما نستخدم ال real-time database نفعلها الاول من Firebase Console فهنفتح الكونسول ونفتح صفحة البروجكت ونضغط علي Realtime Database علي الشمال وبعدين نضغط علي Create Database هيظهر لينا بوب اب يقولنا اختار اللوكيشن بتاع الداتابيز اعمل نكست علطول. هيظهر Popup تاني يقولنا عاوز الداتابيز في ال Locked mode ولا test mode اختار Test mode علشان تقدر تكتب فيها وتقرآ منها واخيرا اضغط علي Enable. وكده الداتابيز جاهزة للاستخدام.

نرجع لصفحة chat.js وفي الاول نكتب ال Imports الي هنحتاجها

import React from 'react'
import {GiftedChat} from 'react-native-gifted-chat'
import database from '@react-native-firebase/database';
import auth from '@react-native-firebase/auth';

ال GiftedChat هي المكتبة الي نزلناها في بداية المقال علشان ترسم لينا صفحة الشات

المرة دي هنعمل Class Component وفي الحالة دي هنستخدم ال State بشكلها العادي بدون اي هوكس

هنعرف في اول الكلاس ال State دي مع الاحتفاظ بشكل اوبجكت ال messages لان دا الشكل الخاص بمكتبة GiftedChat

    state = {
        messages: [
            {
                _id: 1,
                text: 'Welcome, ' + auth().currentUser.email,
                createdAt: new Date(),
                system: true,
            }
        ]
    }

وبعد كده هنعرف الميثود الي اسمها onSend الي بنبعتليها الرساله بعد ما اليوزر بيضغط Send وهيبقي شكلها كالتالي:

    onSend = ((message) => {
        database()
            .ref('/chat/')
            .push(message)
    })

ال onSend عبارة عن ميثود بسيطة بتستخدم فانكشن database الموجودة في الفايربيز وبتروح لمسار سميناه Chat وتقدر تسمية زي ماتحب حتي لو مش موجود هيتم انشاءه اوتوماتيك وهتعمل push او اضافة للرسالة الاخيرة الي تم ارسالها.

كدة لو فتحنا كونسول الفايربيز وضغطنا علي Realtime Database هنلاقي مسار تم انشاءه اسمة chat وجواه الرسايل الي تم ارسالها. (جرب قبل ما تشيك علي الفايربيز تبعت كام رسالة الاول)

كده حفظنا الرسايل في الداتابيز ومحتاجين دلوقتي نعرضها في ال Realtime في صفحة الدردشة وكمان محتاجين دا يحصل اول ما اليوزر يفتح الصفحة او بعد ما يعمل لوجن. في الحالة دي هنستخدم componentDidMount علشان نضمن ان دا يحصل اول ما اليوزر يفتح الشاشة. وهيكون شكلها كالتالي:

    componentDidMount() {

        database()
            .ref('/chat/')
            .limitToLast(1)
            .on('child_added', snapshot => {
                this.setState(previousState => ({
                    messages: GiftedChat.append(previousState.messages, snapshot.val()),
                }))
            });
    }


ودا الشكل النهائي لصفحة Chat.js

import React from 'react'
import {GiftedChat} from 'react-native-gifted-chat'
import database from '@react-native-firebase/database';
import auth from '@react-native-firebase/auth';

export default class Chat extends React.Component {


    state = {
        messages: [
            {
                _id: 1,
                text: 'Welcome, ' + auth().currentUser.email,
                createdAt: new Date(),
                system: true,
            }
        ]
    }

    componentDidMount() {

        database()
            .ref('/chat/')
            .limitToLast(1)
            .on('child_added', snapshot => {
                this.setState(previousState => ({
                    messages: GiftedChat.append(previousState.messages, snapshot.val()),
                }))
            });
    }


    render() {
        return (
            <GiftedChat
                messages={this.state.messages}
                onSend={message => this.onSend(message)}
                showUserAvatar={true}
                renderUsernameOnMessage={true}
                renderAvatarOnTop={true}
                multiline={false}
                user={{
                    name: auth().currentUser.email,
                    _id: auth().currentUser.email,
                    avatar: 'https://placeimg.com/140/140/any'
                }}
            />
        )
    }

    onSend = ((message) => {
        database()
            .ref('/chat/')
            .push(message)
    })
}

نعمل Run للتطبيق تاني ونجرب نرسل رسالة المفروض يتم حفظها في الداتابيز ونشوفها ظهرت قدامنا في الشات.

ودا فيديو للشكل النهائي للتطبيق:

اتمني تكونوا استمتعوا بالشرح والتطبيق اشتغل معاكم مظبوط. لو محتاجين الشرح بالكامل فيديو عرفوني في التعليقات. لو عندكم اي استفسارات اكتبولي في التعليقات وهحاول اساعدكم.

نشر بواسطة

Hosam Zewain

Software Engineer, Operations Director

hosam@hosamzewain.com

التعليقات

maryam areda

maryam الأربعاء مارس 31, 2021

thanks alot


اترك تعليقك هنا

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *


تفاصيل المقالة

فئة Technology الكل
المشاهدات
تاريخ النشر 25 يناير، 2021
علامات