I am building a quiz that randomizes 20 items from a data array. Each quiz question plays a video with a judo technique and the player tries to identify the technique shown. Once an answer is clicked on (right or wrong), it counts the score and moves on to the next video.
PROBLEM - It doesn't play on load even though it has shouldPlay in the props. Oddly enough, the videos play automatically after the game is over and you click on Play Again. When I load the screen and I play it manually, if I pause it, I notice the next item on the quiz loads the next video but it plays from the position on which I paused the previous video <-- that lost me completely.
SOLUTION - Essentially, autoplay from the beginning on each question. I'm kinda new to React Native but I'm sure some of you may find this a rather silly issue lol
I appreciate your help
import React, {useState, useEffect} from 'react'
import { StyleSheet, Text, View } from 'react-native'
import * as Progress from 'react-native-progress';
import theme from '../assets/theme'
import CustomButton from './CustomButton';
import { Video } from 'expo-av';
const VideoPlay = ({data, shouldPlay}) => {
return (
<View style={styles.videoitems}>
<Video
source={{ uri: `https://judopedia.wiki/assets/videos/${data}` }}
resizeMode="contain"
shouldPlay={shouldPlay}
style={styles.video}
useNativeControls
/>
</View>
)
}
const VideoTriviaGame = ({data}) => {
const [currentQuestion, setCurrentQuestion] = useState(0)
const [score, setScore] = useState(0)
const [showScore, setShowScore] = useState(false)
const [quizData, setQuizData] = useState([]);
const [progress, setProgress] = useState(0);
useEffect(() => {
const random = [...data].sort(() => Math.random()).slice(0, 20);
setQuizData(random);
}, [])
const handleAnswer = (selectedAnswer) => {
const answer = quizData[currentQuestion]?.answer;
if(answer === selectedAnswer){
setScore((prevScore)=> prevScore + 1)
}
handleNextQuestion()
}
const handleNextQuestion = () => {
const nextQuestion = currentQuestion + 1;
if(nextQuestion < quizData.length){
setCurrentQuestion(nextQuestion)
if (progress < quizData.length - 1) {
setProgress(progress + .05);
}
} else {
setShowScore(true)
}
}
const handleRestart = () => {
setCurrentQuestion(0)
setScore(0)
setShowScore(false)
setProgress(0);
}
return (
<View style={{flex:1}}>
{showScore
? null
: <VideoPlay data={quizData[currentQuestion]?.url} shouldPlay/>
}
{showScore
?
<View style={styles.gamecnt}>
<View style={{flex:1, alignItems:"center", justifyContent:"center", width:"100%"}}>
<Text style={{color: theme.colors.white, fontSize:24, textAlign:"center", marginBottom:10}}>
You scored {score} out of {quizData.length}
</Text>
<View style={styles.btnGroup}>
<CustomButton text="Play Again" primary onPress={handleRestart}/>
</View>
</View>
</View>
:
<View style={styles.gamecnt}>
<View style={{display:"flex", alignItems:"center"}}>
<Text style={styles.counter}>
{Math.round(progress * 20) + 1 } of {quizData.length}
</Text>
<Progress.Bar
progress={progress+0.05}
width={300}
animated={true}
unfilledColor={theme.colors.darkgray}
color={theme.colors.primaryend}
height={8}
borderWidth={0} />
</View>
<View style={styles.btnGroup}>
{quizData[currentQuestion]?.options.map((item, index) => (
<CustomButton
key={index}
onPress={() => handleAnswer(item)}
text={item} primary
/>
))}
</View>
</View>
}
</View>
)
}
export default VideoTriviaGame
const styles = StyleSheet.create({
counter:{
color: theme.colors.white,
fontSize:18,
fontWeight:"bold",
},
gamecnt:{
flex:1,
alignItems:"center",
justifyContent:"start",
},
btnGroup:{
width:"100%",
},
videoitems: {
flex: 1,
width: '100%',
backgroundColor: '#000',
alignItems: 'center',
justifyContent: 'center',
},
video: {
width: '100%',
height: '100%',
}
})
The Video
component state stays the same as long as it's being rendered, including positionMillis
and isPlaying
, even if you change the video link.
To reset video:
Video
that changes with every new
link.React.useRef
, setStatusAsync
, and adding
ref={videoRef}
to Video
componentRegarding shouldPlay
on start. I copied your code with half of gamecnt
part and it worked fine. It might be some other underlaying issues with your original code, e.g., setting shoulPlay
to null
in a component.
Restart Video on link change:
<Video
key={data} // this will reset video state, every time data changes
source={{ uri: `https://judopedia.wiki/assets/videos/${data}` }}
resizeMode="contain"
shouldPlay={shouldPlay}
style={styles.video}
useNativeControls
/>
Restart Video onPress:
import React from "react";
import { View, Button, SafeAreaView, StatusBar } from "react-native";
import { Video } from "expo-av";
export default function App() {
const videoRef = React.useRef(null);
return (
<SafeAreaView style={{ flex: 1, paddingTop: StatusBar.currentHeight }}>
<Button
title={"Restart"}
onPress={() =>
videoRef.current.setStatusAsync({ shouldPlay: true, positionMillis: 0 })
}
/>
<View style={{ flex: 1, width: "100%" }}>
<Video
ref={videoRef}
style={{ width: "100%", height: "100%" }}
source={{ uri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4"}}
resizeMode="contain"
useNativeControls
/>
</View>
</SafeAreaView>
);
}