I need to show a daily video in my React Native app. This is a randomized video from a local JSON file that has the thumbnail, title, and URL. I have it so that it modifies the state at 00:00:00 hours with a random video from the JSON file. However, on initial load, the state is showing empty. How can I make the randomize function fire once (when they install the app), but only randomize on 00:00:00 hours after that?
import AsyncStorage from '@react-native-async-storage/async-storage';
import dailyvideo from '../assets/data/dailyvideo';
const [time, setTime] = useState(new Date());
const INITIAL_STATE = {
title: 'Seoi Nage',
url: 'seoinage.mp4',
thumbnail: "seionage.jpeg"
}
const [newvideo, setNewVideo] = useState(INITIAL_STATE)
const getTheState = async () => {
const videotitle = await AsyncStorage.getItem("title")
const videourl = await AsyncStorage.getItem("url")
const videothumbnail = await AsyncStorage.getItem("thumbnail")
setNewVideo({
title: videotitle,
url: videourl,
thumbnail: videothumbnail
}
)
}
const handleRandomVideo = async () => {
const randomIndex = Math.floor(Math.random() * allwaza.length);
const randomItem = allwaza[randomIndex];
try {
await AsyncStorage.multiSet(
[
["title", randomItem.title],
["url", randomItem.url],
["thumbnail", randomItem.thumbnail]
]
)
} catch (error) {
console.error(error);
}
}
useEffect(() => {
const interval = setInterval(() => {
setTime(new Date());
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
useEffect(() => {
if (time.getHours() === 0 && time.getMinutes() === 0 && time.getSeconds() ===0) {
handleRandomVideo()
}
getTheState()
}, [time]);
return (
<View>
<Text>Today's Suggested Tech </Text>
<View>
// This fires a VideoPlayer component that handles the URL
<TouchableOpacity onPress={() => navigation.navigate('VideoPlayer', {data: newvideo})}>
<Image source={{uri: newvideo.thumbnail}}/>
</TouchableOpacity>
<Text> {newvideo.title} </Text>
</View>
</View>
)
For clarification, the video shows up and plays when it is set to storage. My issue is, on a fresh install, the storage is empty until the next 00:00:00 hours hit. It's bad UX. I need it to run immediately on a fresh install and then at 00:00:00 after that.
To ensure that the randomization function fires immediately upon fresh install and only at 00:00:00 hrs afterward, you can utilize a combination of useEffect and the AsyncStorage API.
Here's how you can modify your code to achieve this:
import React, { useState, useEffect } from 'react';
import { View, Text, Image, TouchableOpacity } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import dailyvideo from '../assets/data/dailyvideo';
const INITIAL_STATE = {
title: 'Seoi Nage',
url: 'seoinage.mp4',
thumbnail: 'seionage.jpeg'
};
const VideoComponent = ({ navigation }) => {
const [time, setTime] = useState(new Date());
const [newvideo, setNewVideo] = useState(INITIAL_STATE);
const allwaza = dailyvideo; // assuming allwaza is your JSON data
const handleRandomVideo = async () => {
const randomIndex = Math.floor(Math.random() * allwaza.length);
const randomItem = allwaza[randomIndex];
try {
await AsyncStorage.multiSet([
['title', randomItem.title],
['url', randomItem.url],
['thumbnail', randomItem.thumbnail]
]);
setNewVideo(randomItem);
} catch (error) {
console.error(error);
}
};
const getTheState = async () => {
const videotitle = await AsyncStorage.getItem('title');
const videourl = await AsyncStorage.getItem('url');
const videothumbnail = await AsyncStorage.getItem('thumbnail');
if (videotitle && videourl && videothumbnail) {
setNewVideo({
title: videotitle,
url: videourl,
thumbnail: videothumbnail
});
} else {
handleRandomVideo();
}
};
useEffect(() => {
const checkAndSetVideo = async () => {
await getTheState();
const interval = setInterval(() => {
setTime(new Date());
}, 1000);
return () => {
clearInterval(interval);
};
};
checkAndSetVideo();
}, []);
useEffect(() => {
if (
time.getHours() === 0 &&
time.getMinutes() === 0 &&
time.getSeconds() === 0
) {
handleRandomVideo();
}
}, [time]);
return (
<View>
<Text>Today's Suggested Tech </Text>
<View>
<TouchableOpacity
onPress={() => navigation.navigate('VideoPlayer', { data: newvideo })}
>
<Image source={{ uri: newvideo.thumbnail }} />
</TouchableOpacity>
<Text>{newvideo.title}</Text>
</View>
</View>
);
};
export default VideoComponent;
Here's a breakdown of what's happening: