I’m building a React Native gig guide app.
Each gig is represented by a document in the firebase collection and has an associated date property.
I want to display the current day’s gigs to the user. I also the user to tap a "next day’s gigs" button and be shown a list of gigs for the next day, as follows:
I can get the current day’s gigs without issue using the following logic:
const day = new Date().getDate();
const month = new Date().getMonth() + 1;
const year = new Date().getFullYear();
const dateToday = `${day}/${month}/${year}`;
//Filtering through gigs to return only current day's gigs
const gigsToday = gigs.filter((gig) => gig.date === dateToday);
…but how do I show the next/previous day’s gigs?
Here’s what I’ve done so far
1.) Convert the new Date()
to a UTC+13 time:
const addHours = (numOfHours, date = new Date()) => {
date.setTime(date.getTime() + numOfHours * 60 * 60 * 1000);
return date;
};
let localDate = addHours(13);
2.) Set up an onPress event that increments the state variable daysAdded
by 1:
<Pressable onPress={addDay}>
<Text style={styles.buttonOptionsText}>next day's gigs</Text>
</Pressable>
3.) Create a function that adds a day to the localDate
variable, and then set that new date to state variable date
:
const [date, setDate] = useState(dateToday);
...
const addDay = () => {
setDaysAdded(daysAdded + 1);
localDate.setDate(localDate.getDate() + daysAdded);
setDate(localDate);
};
The problem is that the initial date state is not immediately loaded, which means I can’t conditionally render dates based on their date.
I’m confused about something else – I have a date that I want to manipulate, so do I set this date as a variable or a piece of state?
Anyway, ideally once the user presses the "next days gigs" button, the app will conditionally render the gigs for the next day.
I should also mention that the date being returned from my Firebase Firestore is in the form "DD/MM/YYYY"
Full code is as follows:
GigMap.js
import { useState, useEffect } from "react";
import { StyleSheet, Text, View, Pressable } from "react-native";
import MapView from "react-native-maps";
import { Marker, Callout } from "react-native-maps";
import CalloutView from "./CalloutView";
import { mapStyle } from "../util/mapStyle";
import { useGigs } from "../hooks/useGigs";
const GigMap = ({ navigation }) => {
const [date, setDate] = useState(dateToday);
const gigs = useGigs()
const [daysAdded, setDaysAdded] = useState(1);
const addHours = (numOfHours, date = new Date()) => {
date.setTime(date.getTime() + numOfHours * 60 * 60 * 1000);
return date;
};
let localDate = addHours(13);
useEffect(() => {
setDate(localDate);
}, []);
const addDay = () => {
setDaysAdded(daysAdded + 1);
localDate.setDate(localDate.getDate() + daysAdded);
setDate(localDate);
};
//Generating current date
const day = new Date().getDate();
const month = new Date().getMonth() + 1;
const year = new Date().getFullYear();
const dateToday = `${day}/${month}/${year}`;
//Filtering through gigs to return only current day's gigs
const gigsToday = gigs.filter((gig) => gig.date === dateToday);
return (
<View style={styles.container}>
<Text style={styles.headerText}>Today's gigs</Text>
<MapView
initialRegion={{
latitude: -41.29416,
longitude: 174.77782,
latitudeDelta: 0.03,
longitudeDelta: 0.03,
}}
style={styles.map}
customMapStyle={mapStyle}
>
{gigsToday.map((gig, i) => (
<Marker
key={i}
coordinate={{
latitude: gig.location.latitude,
longitude: gig.location.longitude,
}}
image={require("../assets/Icon_Gold_48x48.png")}
>
<Callout
style={styles.callout}
onPress={() =>
navigation.navigate("GigDetails", {
venue: gig.venue,
date: gig.date,
gigName: gig.gigName,
time: gig.time,
})
}
>
<CalloutView
venue={gig.venue}
date={gig.date}
gigName={gig.gigName}
time={gig.time}
style={styles.calloutView}
/>
</Callout>
</Marker>
))}
</MapView>
<View style={styles.buttonOptions}>
<Pressable>
<Text style={styles.buttonOptionsText}>previous day's gigs</Text>
</Pressable>
<Pressable onPress={addDay}>
<Text style={styles.buttonOptionsText}>next day's gigs</Text>
</Pressable>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: "column",
alignItems: "center",
},
map: {
height: 500,
width: 330,
margin: 10,
},
headerText: {
color: "black",
fontSize: 20,
marginTop: 5,
},
callout: {
width: 200,
height: 100,
},
buttonOptions: {
flexDirection: "row",
justifyContent: "flex-start",
},
buttonOptionsText: {
margin: 5,
},
});
export default GigMap;
2
Answers
I think you are overcomplicating things. First of all you don’t need to create all new individual
Date
objects just to get the date, month and year. Secondly, you can get the date formatted the way you want by usingtoLocaleDateString()
and specifying the locale for the style of formatting you want. And thirdly, the native JavaScriptDate
object handles month and year boundaries automatically if you usesetDate()
.Your code is not timezones-aware and it has a lot of logic and variables outside of the react state management functions which could cause bugs due to the fact that variables will be recreated and functions will be called on each render. You should use
useState
anduseMemo
more frequently. Do not rely on raw variables and functions calls until you clearly know what you are doing.