Appearance
Chatten in de chat applicatie
Inhoud
Ondertussen kunnen gebruikers zich registreren en aanmelden in de applicatie. In dit deel gaan we de chat applicatie afwerken door de WebSocket communicatie te implementeren.
Voordat we berichten kunnen gaan uitwisselen, moeten we eerst de connectie met de server kunnen opzetten en moeten we de beschikbare kamers kunnen ophalen. In zo een kamer gaan we uiteindelijk de chatberichten kunnen uitwisselen. Daarom passen we eerst het volgende toe:
- We integreren de cliënt API van Socket.io
- We maken een bestand aan dat de connectie gaat beheren
- We breiden de context van de applicatie uit zodat we de chat state kunnen beheren
- We implenteren de chatrooms functionaliteit
De Socket.io client API
Om de client API van Socket.io in ons React Native project te kunnen gebruiken kunnen we een expo pakket installeren.
Take The Wheel
Navigeer naar de root van je project in de terminal en installeer het pakket met het volgende commando: npx expo install socket.io-client
Het Socket.io object
Om de connectie met de server te kunnen maken, gaan we het Socket object moeten aanmaken. Hiervoor gaan we een hulpbestand aanmaken, zodat we dit object vanuit verschillende plaatsen in de applicatie kunnen aanspreken.
Take The Wheel
- Maak een nieuwe map met de naam utils aan in de root van je project
- Maak in deze map een bestand met de naam socket.ts aan
- Importeer de Socket.IO-client library
- Exporteer een socket constante die is geconfigureerd met het IP-adres en de poort van je server
- Stel de autoConnect optie in op false om automatisch verbinden bij het starten van de app te voorkomen. Gebruikers moeten namelijk ingelogd zijn om te kunnen chatten.
Belangrijke opmerkingen over de verbinding:
Gebruik voor lokale ontwikkeling met verschillende apparaatinstellingen het juiste IP-adres:
- Zelfde machine (web en iOS): Gebruik localhost
- Android-emulator op dezelfde machine als de server: Gebruik het adres van de Metro Bundler. Bijvoorbeeld 192.168.0.231
- Fysiek apparaat of aparte computer: Gebruik het werkelijke IP-adres van de server
De ChatContext uitbreiden
In de Context van onze applicatie hebben we tot nu toe alle functionaliteit geschreven waarbij een gebruiker kan registreren en aanmelden. Nu gaan we de functionaliteit toevoegen zodat gebruikers kunnen chatten.
Het socket object
Take The Wheel
- Importeer het socketobject uit het utilitybestand
Statevariabelen
Voeg de volgende statevariabelen toe:
Take The Wheel
- isConnected (boolean): Houdt bij of de WebSocket verbonden is
- transport (string): Slaat informatie op over het transport dat wordt gebruikt
- roomsListing (array): Slaat de lijst van beschikbare chatrooms op
- chatMessages (array): Slaat berichten op voor de huidige chatruimte
- userMessage (string): Slaat het huidige bericht op dat wordt ingegeven door de gebruiker
Functies
Functies voor de connectie
Voeg de volgende functies toe om de state van de connectie te beheren:
Take The Wheel
- chatConnect:
- Stelt isConnected in op true
- Update de transportstatus met het huidige transporttype van de socket. Hiermee kunnen we detecteren welk protocol gebruikt wordt (http of websocket)tsx
setTransport(socket.io.engine.transport.name); socket.io.engine.on('upgrade', (transport) => { setTransport(transport.name) });
- chatDisconnect:
- Verbreekt de verbinding met de server met behulp van de disconnect methode van de socket
- Stelt isConnected in op false
- Reset de transportstatus naar "N/A"
- chatConnection:
- Controleert of de WebSocket al verbonden is. Indien verbonden, wordt de chatConnect functie aangeroepen. Indien niet verbonden, wordt een verbinding gemaakt met behulp van de connect methode van de socket
- Stelt event listeners in op de socket voor connect- en disconnect-events
- Verwijdert de event listeners wanneer het component wordt losgekoppeld. (Dit gebeurt in de return van de functie.)
Functies voor de chatrooms
Voeg de volgende functies toe om berwerkingen met de chat rooms te beheren:
Take The Wheel
- getRooms:
- Verstuurt een getRooms-event om de lijst met beschikbare chatrooms op te vragen (Tip: socket.emit)
- listRooms:
- Luistert naar het returnRooms event van de server
- werkt de status van roomsListing bij met de ontvangen gegevens
- joinRoom:
- Heeft een kamer-ID en gebruikersnaam als parameters
- Maakt een constante aan om de huidige lokale datum en tijd te verkrijgen
- Creëert een systeembericht dat de toegang van de gebruiker tot de kamer aankondigt
- Verstuurt een connectRoom event met de kamer ID naar de server
- Luistert naar het joinedRoom event om de bestaande kamerberichten te ontvangen en werkt de status van chatMessages bij met de ontvangen berichten
- Gebruikt de sendMessage methode (die in de volgende stap wordt aangemaakt) om het systeembericht naar de kamer te verzenden.
Functies voor de berichten
Voeg de volgende functies toe om de chat berichten te beheren:
Take The Wheel
handleChatMessages:
- Werkt de lokale opslag van chatberichten bij, wanneer een nieuw bericht wordt ontvangen
sendMessage:
- Heeft een bericht, de kamer-ID en de naam van de gebruiker als parameters
- Controleert of de inhoud van het bericht niet leeg is
- Maakt een constante aan om de huidige lokale datum en tijd te verkrijgen
- Stuurt een newPost event met de berichtgegevens naar de server
- Wist het invoerveld door de status van userMessage te resetten
- Geeft een Alert weer als de gebruiker een leeg bericht probeert te verzenden. (Zal alleen op mobiel werken)
Variabelen en functies ter beschikking stellen van de context
Tenslotte moeten we in andere bestanden gebruik kunnen maken van de context. Doe hiervoor het volgende:
Take The Wheel
- Voeg alle statevariabelen toe aan het context object
- Voeg alle functies toe aan het context object
- Neem het socket object op in het context object
De connectie beheren bij navigatie
De connectie moet opnieuw gesloten worden wanneer we navigeren naar de startpagina. Hiervoor gaan we variabelen en functies gebruiken die we net aan de context hebben toegevoegd.
Take The Wheel
- Importeer de ChatContext, useEffect en useContext
- Haal de isConnected state variabele en de chatDisconnect functie op van de context.
- Implementeer een useEffect-hook die de WebSocket verbreekt wanneer naar de startpagina wordt genavigeerd, als er een connectie is gemaakt.
De chatkamer
Ondertussen krijgen we alle chatkamers te zien. De volgende stap is dat wanneer we navigeren naar een specifieke chatkamer, we daar ook effectief berichten kunnen sturen. De functionaliteit hiervoor gaan we onderbrengen in een nieuw bestand
Take The Wheel
Maak een nieuw bestand room.tsx aan in jouw project.
Imports
In room.tsx importeren we de componenten en de methodes die we nodig gaan hebben en maken we een constante aan om de hoogte van het scherm op te vragen, zodat de applicatie dynamisch kan schalen afhankelijk van het toestel.
Take The Wheel
- Importeer de volgende React Native componenten:
- StyleSheet
- Text
- View
- Dimensions
- Platform
- FlatList
- TextInput
- TouchableOpacity
- Importeer useEffect, useRef, useLayoutEffect en useContext van React
- Importeer useLocalSearchParams van expo-router
- Importeer de ChatContext
- Maak een constante
boundedHeightaan om de hoogte van het venster te verkrijgen door gebruik te maken van hetDimensionscomponent.
Het Room Component
In het room component gaan we de functionaliteit onderbrengen om de effectieve chatberichten te verwerken. Hierin voorzien we volgende functionaliteit:
De routeparameters uit het Request halen.
Om te weten in welke kamer we zitten en wie de gebruiker is, hebben we gewerkt met routeparameters die we doorgeven op het moment dat er op een kamer wordt geklikt. Die routeparameters willen we nu terug opvragen. Dit doen we door het volgende te implementeren:
Take The Wheel
- De parameters kunnen we opvragen door gebruik te maken van
useLocalSearchParams. Vang de volgende parameters op:- room_id: dat het id van de kamer bevat
- roomTitle: dat de titel van de kamer bevat
- sender: dat de gebruiksnaam van de ingelogde gebruiker bevat.
Maak eventueel gebruik van de documentatie om de juiste syntax te bekijken.
De vereiste variabelen en functies uit de ChatContext opvragen
In de chatkamer gaan we gebruik maken van de context (state) die we via onze ChatContext bijhouden. Daarom gaan we een aantal variabelen en functies opvragen uit deze context.
Take The Wheel
Maak gebruik van useContext om de volgende variabelen en functies op te halen uit ChatContext:
- chatMessages: dat een Array van de berichten voor de huidige kamer zal bevatten.
- joinRoom: de functie om met een chatkamer te verbinden.
- userMessage: het huidige bericht dat we gaan opstellen en versturen.
- setUserMessage: de functie om het bericht te updaten.
- sendMessage: de functie om het bericht naar de server te sturen.
- handleChatMessages: de functie die binnenkomende berichten gaat afhandelen.
- socket: Het Socket.IO connection object
Bekijk de functies en variabelen in de ChatContext nog eens, indien je niet meer goed weet wat die precies doen.
Een verwijzing naar een FlatList
We willen dat wanneer er berichten worden gepost en ontvangen, dat de FlatList waarbinnen de berichten gaan getoond worden, automatisch scrolt. Hiervoor dienen we een referentie of verwijzing naar de FlatList bij te houden. Zonder een referentie kunnen we dat scrollgedrag niet automatisch regelen. Door het aanmaken van een referentie krijgen we ook toegang tot verschillende methodes. Bijvoorbeeld:
- scrollToEnd: Scrolt naar het einde van de lijst (handig voor het tonen van de laatste berichten)
- scrollToIndex: Scrollt naar een specifiek item op index
- scrollToItem: Scrollt naar een specifiek item in de gegevens
- scrollToOffset: Scrollt naar een specifieke offset
Wij gaan uiteindelijk gebruik maken van de scrollToEnd methode.
Take The Wheel
Maak gebruik van useRef om een referentie (flatListRef) naar een FlatList aan te maken.
Verschillende lifecycle hooks implementeren
Take The Wheel
useLayoutEffect hook:
- Deze hook moet enkel uitgevoerd worden wanneer het component wordt gemount.
- Roept de joinRoom functie aan met het room_id, dat je via de parameters hebt binnengekregen, om een connectie te maken met de geselecteerde kamer.
- Maakt gebruik van de FlatList referentie om te scrollen naar de meest recente berichten.
useEffect hook
- Deze hook moet elke keer uitgevoerd worden wanneer het socket object wijzigt.
- Zorgt ervoor dat het socket object luistert naar het newMessage event (Dat vanuit de server wordt doorgegeven).
- Wanneer het event binnenkomt, spreek je de handleChatMessages functie aan zodat de chat wordt geüpdatet.
een sendPost functie
- Deze functie zal de sendMessage functie uit de ChatContext aanroepen om een bericht te versturen. Deze functie verwacht de userMessage, de room_id en de sender als argument
Een aparte component voor een bericht
Binnen het bestand gaan we een apart component aanmaken dat een bericht gaat vertegenwoordigen en dat we binnen de FlatList gaan kunnen gebruiken. Dit component moet zowel eigen geschreven berichten als berichten van andere personen kunnen weergeven. We gaan dit onderscheid maken door de berichten een andere stijl te geven.
Take The Wheel
- Maak een constante MessageComponent aan. Deze constante heeft een functie als waarde.
- De functie heeft de volgende parameters:
- content: de content van het bericht
- sent: het tijdstip dat het bericht werd verzonden
- user: de gebruiker die het bericht heeft verzonden
- sender: de huidige ingelogde gebruiker
- Maak binnen de functie een variabele origin aan, waarmee je gaat bepalen of het bericht van de huidige gebruiker is of van een andere gebruiker.
- Return een template die als volgt is samengesteld:
- View: de stijl is afhankelijk van de gebruiker. Is origin
true, geef danroomMessageContainerals klasse, anders geef jemyMessageContainerals klasse. Voorzie binnen deze View:- View: de stijl is afhankelijk van de gebruiker. Is origin
true, geef danroomMessageals klasse, anders geef jemyMessageals klasse. Voorzie binnen deze View:- Een Text component waarbinnen de content wordt weergegeven. De stijl is afhankelijk van de gebruiker. Is origin
true, geef danroomTextals klasse, anders geef jemyTextals klasse.
- Een Text component waarbinnen de content wordt weergegeven. De stijl is afhankelijk van de gebruiker. Is origin
- View: die je de klasse
userRowgeeft. Voorzie binnen deze View:- Een Text component waarbinnen de waarde van user wordt weergegeven en die je de klasse
infogeeft. - Een Text component waarbinnen de waarde van sent wordt weergegevenen die je de klasse
infogeeft.
- Een Text component waarbinnen de waarde van user wordt weergegeven en die je de klasse
- View: de stijl is afhankelijk van de gebruiker. Is origin
- View: de stijl is afhankelijk van de gebruiker. Is origin
De Room template
Tenslotte bouwen we de UI voor de pagina waarop de chatberichten worden weergegeven. Bouw dit als volgt op:
Take The Wheel
Begin met een View component als hoofdcontainer die je de klasse container geeft.
Voeg een Text component toe om de titel van de kamer weer te geven die je de klasse
titlegeeft.Voeg nog een Text component toe om de naam van de huidige gebruiker weer te geven die je de klasse
usergeeft.Voeg een View component toe die je de klasse
listViewgeeft. Hierin voorzie je een FlatList dat je als volgt instelt:- Wijs de flatListRef toe aan de ref prop
- Stel de data prop in op chatMessages
- Gebruik het MessageComponent voor de renderItem prop en geef zowel het berichtitem als de afzender door aan het MessageComponent
- Gebruik het id van het bericht voor de keyExtractor prop
- Stel inverted in op
falseom de nieuwste berichten onderaan te tonen - Voeg een onContentSizeChange handler toe om te scrollen wanneer er nieuwe berichten binnenkomen (maak hiervoor gebruik van de juiste functie op de flatListRef)
Een View component voor het invoergedeelte voor berichten, die je de klasse
messaginggeeft. Voorzie hierbinnen:- een Text component toe met het label "Jouw Bericht" die je de klasse
formLabelgeeft - een TextInput component toe:
- Bind de waarde ervan aan userMessage
- Stel onChangeText in op setUserMessage
- Geef dit component de klasse
formInput
- een TouchableOpacity component toe als verzendknop:
- Stel onPress in om de functie sendPost aan te roepen
- Voeg een geschikte tekst of pictogram voor de knop toe
- een Text component toe met het label "Jouw Bericht" die je de klasse
De stijl
Om geen tijd te verliezen met het opmaken van de componenten kan je hieronder basis stijl terugvinden:
tsx
const styles = StyleSheet.create({
container: {
height: boundedHeight,
},
title: {
fontWeight: 'bold',
alignSelf: 'center',
textDecorationLine: 'underline',
...Platform.select({
android: {
fontSize: 24,
paddingVertical: 5,
},
ios: {
fontSize: 24,
paddingVertical: 5
},
default: {
fontSize: 30,
paddingVertical: 10
}
})
},
user: {
fontWeight: 'bold',
...Platform.select({
android: {
fontSize: 20,
paddingVertical: 5
},
ios: {
fontSize: 20,
paddingVertical: 5
},
default: {
fontSize: 24,
paddingVertical: 10
}
})
},
listView: {
height: '40%',
paddingTop: 20,
borderWidth: 1
},
messaging: {
height: '60%'
},
roomMessageContainer: {
width: '45%',
paddingBottom: 15
},
myMessageContainer: {
width: '45%',
alignSelf: 'flex-end',
paddingBottom: 15
},
roomMessage: {
backgroundColor: '#1E90FF',
borderRadius: 8
},
myMessage: {
backgroundColor: '#949494',
borderRadius: 8
},
roomText: {
fontSize: 24,
paddingVertical: 10,
paddingHorizontal: 5,
color: '#ffffff'
},
myText: {
fontSize: 24,
paddingVertical: 10,
paddingHorizontal: 5,
},
userRow: {
flexDirection: 'row',
justifyContent: 'space-evenly'
},
info: {
fontWeight: 'bold',
...Platform.select({
android: {
fontSize: 12,
paddingTop: 10
},
ios: {
fontSize: 12,
paddingTop: 10
},
default: {
fontSize: 24,
paddingTop: 18
}
})
},
formLabel: {
alignSelf: 'center',
...Platform.select({
android: {
fontSize: 16,
paddingVertical: 10
},
ios: {
fontSize: 16,
paddingVertical: 10
},
default: {
fontSize: 24,
paddingVertical: 18
}
})
},
formInput: {
width: 350,
borderWidth: 1,
padding: 10,
alignSelf: 'center',
...Platform.select({
android: {
fontSize: 16,
},
ios: {
fontSize: 16,
},
default: {
fontSize: 24,
width: 400
}
})
},
formButtonLabel: {
alignSelf: 'center',
...Platform.select({
android: {
fontSize: 22,
paddingTop: 12
},
ios: {
fontSize: 22,
paddingTop: 12
},
default: {
fontSize: 30,
paddingTop: 20
}
})
}
});