Deze Travel app dient als een soort Instagram maar dan voor reizigers, waarbij de gebruiker foto’s kan delen met andere in een soort feed
Na de ontwikkeling van de Food delivery app
heb ik mijn opgedaane kennis toepgepast in deze Travel-app. Deze app heb ik ontwikkeld om mijn kennis en vaardigheden te verbeteren omtrent development. Tijdens het ontwikkelproces heb ik de structuur van Freshheads gevolgd en feedback van mijn stagebegeleider Kevin geïntegreerd om de codekwaliteit te verbeteren. Mijn doel was ook om de mogelijkheden te verkennen in Expo web
en te kijken hoe het is om zowel voor mobile als web gelijktijdig deze app de ontwikkelen.
- travel-app
- ProgramData
- (app)
- _layout.tsx
- homeScreen.tsx
- searchTourScreen.tsx
- settingsScreen.tsx
- yourTourScreen.tsx
- (auth)
- _layout.tsx
- loginScreen.tsx
- registerScreen.tsx
- verifyScreen.tsx
- index.tsx
- assets
- img
- adaptive-icon.png
- favicon.png
- icon.png
- splash.png
- img
- components
- webComponents
- container.tsx
- container.web.tsx
- LoginInput.tsx
- Postcard.tsx
- ProfileCard.tsx
- SignUpInput.tsx
- StartButton.tsx
- shared
- .gitignore
- app.json
- babel.config.js
- package-lock.json
- webComponents
In mijn Food delivery app
heb ik voor het eerst kennisgemaakt met Expo-routing
, dat onderliggend React-navigation
gebruikt. Expo-routing
maakt gebruik van routing op basis van bestanden, waardoor je eenvoudig de lay-out binnen je app kunt realiseren. Bij het ontwikkelen van mijn Travel-app was het in het begin lastig om goed te begrijpen, omdat je rekening moet houden met hoe je de mappenstructuur opzet. Maar zodra je het doorhebt, vergeet je het niet meer. Natuurlijk zijn er verschillende manieren om je structuur in te delen. In mijn Travel-app heb ik in de app
-map een _Layout.tsx
gemaakt onder elke map. Deze _Layout.tsx
bepaalt hoe bepaalde schermen worden weergegeven, bijvoorbeeld door een stack.Screen
of een modal te gebruiken. Je kunt aan deze schermen natuurlijk eigenschappen meegeven, zoals een Header
of juist niet. Hier is een voorbeeld van hoe ik dit in de (auth)
-map heb gedaan:
// _Layout.tsx indeling
import React from "react";
import { Stack } from "expo-router";
const Layout = () => {
return (
<Stack>
<Stack.Screen
name="loginScreen"
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="registerScreen"
options={{
presentation: 'card',
headerShown: false,
}}
/>
<Stack.Screen
name="verifyScreen"
options={{
presentation: 'modal',
}}
/>
</Stack>
);
};
export default Layout;
Screen.Recording.2023-12-08.at.14.43.28.mov
Om naar een andere ander scherm te navigeren moet je gebruik maken van Link
dat vanuit Expo-router
werkt. Dit voorbeeld komt van loginScreen.tsx
.
//voorbeeld linking
<Link href={"/(auth)/registerScreen"} asChild>
<Button title="Sign up" color={theming.text} />
</Link>
In de Link
zit een href
die navigeert naar het scherm dat geopend moet worden. Als je wilt linken naar een scherm maar wilt voorkomen dat de gebruiker teruggaat, kun je de eigenschap replace
toevoegen. Het is echter belangrijk op te merken dat dit niet volledig veilig is, omdat gebruikers op het web de link kunnen aanpassen en alsnog terug kunnen gaan. In mijn geval heb ik dit zo gehouden omdat mijn focus lag op het begrijpen van Expo, Typescript en Expo-routing. Hier is een voorbeeld van het gebruik van replace
:
//voorbeeld gebruik van replace
<Link href={"/(app)/homeScreen"} replace asChild>
<Button title="Sign in" color={"#fff"} />
</Link>
Screen.Recording.2023-12-08.at.15.22.36.mov
Dit component bestaat uit de afbeelding en informatie die de gebruiker erbij gezet heeft, in een volledig concept zou de gebruiker ook daadwerkeijk kunnen liken en commenten, maar in dit geval ging het om de mogelijkheden verkennen binnen Expo. Voor dit component heb ik vaste data gebruikt dat er als voorbeeld zo uitziet.
const DATA = [
{
id: "1",
avatar: require("../assets/img/Avatar.jpg"),
name: "Max",
location: "Washington",
image: require("../assets/img/afbeelding1.jpg"),
title:
"lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptate deserunt dolor sequi.",
},
// rest van data
Omdat ik TypeScript gebruik moet je de types definnieren. Door dit te doen maak je je code overzichterlijker en overdraagbaar omdat je zo bepaalde types vast legt en dus ook geen verwarring kan onstaan. een voorbeeld hiervan is dat je van een nummer een string
kunt maken, als je dan bijvoorbeeld een int
in de type
mee geeft dan wordt er aangegevn dat deze type niet verwacht word. Aan de hand van de data kun je bepaalen of dat een type een nummer
, boolean
, string
enzovoort. Dit zou er zo uit kunnen zien:
type ItemProps = {
id: string;
avatar: any;
name: string;
location: string;
image: any;
title: string;
};
Binnen de PostCard
heb ik een extra component ontwikkeld genaamd ImageList
. Deze ImageList
zorgt voor de content die zich binnen de PostCard
bevind. Deze ImageList
zit in een FlatList
. Een FlatList
zorgt ervoor dat niet alles in één keer gerenderd word, maar alleen wat zichtbaar is op de telefoon zelf. Dit zorgt ervoor dat de prestaties van je app optimaal blijven en geen lange laad tijden voort komen. In mijn geval heb ik niet veel data dus zal het niet veel in prestatie achteruit gaan mocht ik FlatList
niet gebruikt hebben, maar als je dus in het geval van Instagram of TikTok bijvoorbeeld kijken waarbij je misschien wel 1000+ aan content hebt dan zal dat natuurlijk fout gaan als dit in één keer geladen moet worden. Door deze reden wordt FlatList
dus vrijwel altijd toegepast. In mijn code heb ik het als volgt aangepast:
const PostCard = () => {
return (
<FlatList
data={DATA}
renderItem={({ item }) => <ImageList {...item} />}
keyExtractor={(item) => item.id}
/>
);
};
Binnen de PostCard
bevind zich de ImageList
component. Deze ImageList
component zorgt voor de inhoud van de PostCard
. Met inhout bedoel ik onder andere de avatar, comment box, locatie, foto's en liken.
Door
renderItem={({ item }) => <ImageList {...item} />}
Binnen de FlatList
te gebruiken, worden de items opgehaald uit de DATA. Welke items je uit de DATA wilt halen kun je onder andere doen door {...items}
, zo zorg je ervoor dat alle items gedefinieerd moeten worden in je ImageList
. Je zou ook speciefieke items kunnen meegeven zoals id, avatar en name, dan zou je alleen deze specifieke items moeten definiëren in je ImageList
.
In mijn ImageList
heb ik vervolgens items meegegeven die gebruikt kunnen worden voor mijn ImageList
. Dat heb ik op deze manier gedaan:
const ImageList = ({ image, title, id, avatar, name, location }: ItemProps) => {
vervolgens kun je deze items
die uit de DATA gehaald worden oproepen in je code. Hier een voorbeeld
<View style={styles.container}>
<TouchableOpacity>
<Image
style={styles.profilePlacement}
source={avatar}
/>
</TouchableOpacity>
<View style={styles.textContent}>
<Text style={styles.textWelcome}>{name}</Text>
<Text style={styles.textName}>{location}</Text>
</View>
<TouchableOpacity style={styles.iconPlacement}>
<Ionicons name="arrow-forward-outline" size={23} />
</TouchableOpacity>
</View>
Door {}
te gebruiken haal je de DATA gemakkelijk op.
Naar aanleiding van de hoofdvraag van mijn onderzoek, ben ik gaan kijken wat er nu gebeurd als ik mijn expo app omzet naar een website. Mijn bevinding hiervan heb ik beschreven in mijn portfolio onder onderzoek Expo/web
. Expo web werkt naar mijn mening nog niet optimaal. het gaat vooral om native funcionaliteiten die niet goed werken op web. Je schrijft ook te speciefieke code voor elk platform waardoor het negatief kan uitslaan op prestatie en laadtijd als je zowel web als app in één code base hebt.