How to make a countdown timer in react native? - react-native

I have to make a countdown timer in an react-native app but i dont know how, i already looked it up and and found some librarys such as react-native-countdown component but it didnt worked as id like, and got some other solutions like setInterval but i dont know how to implement it in my code and make it display on the screen as in the images below:
The time goes from 00:00 to 60:00 (MM:SS) as the user slides the bar, that changes the number 05:00 by 05:00, ive already done that but with a static number, i couldnt make it countdown.
Heres how my code is looking right now:
import { useNavigation } from '#react-navigation/core';
import React, { useEffect, useState } from 'react';
import { SafeAreaView, Text, Image, TouchableOpacity, StyleSheet, Dimensions, TextInput, KeyboardAvoidingView, Platform, View } from 'react-native';
import Slider from '#react-native-community/slider';
import CountDown from 'react-native-countdown-component';
import abacatezinImg from '../assets/abacatezinin.png';
import botaoStop from '../assets/botaoStop.png';
import botaoPlay from '../assets/botaoPlay.png';
export function Timer(){
const [range, setRange] = useState('0');
const [sliding, setSliding] = useState('Inactive');
const [isSecureEntry,setIsSecureEntry]=useState(true);
const navigation = useNavigation<any>();
function handleQuit(){
navigation.navigate('Quit');
}
if(isSecureEntry){
return(
<SafeAreaView style={styles.container}>
<Text style={styles.texto}>{range}</Text>
<View style={styles.container2}>
<Slider
style={styles.slider}
minimumValue={0}
maximumValue={60}
minimumTrackTintColor='#7E9F70'
maximumTrackTintColor='#A7C99A'
thumbImage={abacatezinImg}
value={30}
onValueChange={value => setRange(parseInt(value) + ':00')}
onSlidingStart={() => setSliding('Sliding')}
onSlidingComplete={() => setSliding('Inactive')}
step={5}
/>
<TouchableOpacity onPress={() =>{
setIsSecureEntry((prev)=> !prev)
}}>
<Image source={botaoPlay} style={styles.bPlay}/>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
else{
return(
<SafeAreaView style={styles.container}>
<Text style={styles.texto}>{range}</Text>
<View style={styles.container3}>
<TouchableOpacity onPress={handleQuit}>
<Image source={botaoStop} style={styles.bStop}/>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
alignItems: 'center',
justifyContent: 'flex-start',
},
container2:{
backgroundColor: '#E4F0E2',
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
borderRadius: 100,
width: 327,
height: 66,
paddingHorizontal: 19,
marginTop: 20,
},
container3:{
alignItems: 'center',
justifyContent:'space-between',
marginTop: 20,
},
slider:{
width: 209,
height: 50,
transform: [{scaleY: 4}]
},
bPlay:{
width: 50,
height: 50,
},
bStop:{
width: 66,
height: 66,
},
texto:{
fontWeight: '300',
fontSize: 58,
lineHeight: 87,
letterSpacing: 0.03,
color: '#1B3810',
},
})
If anyone has any idea how to make it Id appreciate the help

Hooks(using useEffect) to countdown using setInterval in react - native:
const [timerCount, setTimer] = useState(60)
useEffect(() => {
let interval = setInterval(() => {
setTimer(lastTimerCount => {
if (lastTimerCount == 0) {
//your redirection to Quit screen
} else {
lastTimerCount <= 1 && clearInterval(interval)
return lastTimerCount - 1
}
})
}, 1000) //each count lasts for a second
//cleanup the interval on complete
return () => clearInterval(interval)
}, []);
use the state variable timerCount as:
<Text>{timerCount}</Text>

Related

Text strings must be rendered within a <Text> component. When creating a button

I'm new to react native and trying to create a button, here is my StartScreen:
import React from 'react' import Background from '../components/Background' import AppButton from '../components/AppButton'
export default function StartScreen({ navigation }) {
return(
<Background>
<AppButton title="HEEEY!" size="sm" backgroundColor="#007bff" />;
</Background>
) }
Here is my AppButton:
import React from 'react'
import { StyleSheet, TouchableOpacity, Text } from "react-native";
export default function AppButton ({ onPress, title, size, backgroundColor }) {
return (
<TouchableOpacity
onPress={onPress}
style={[
styles.appButtonContainer,
size === "sm" && {
paddingHorizontal: 8,
paddingVertical: 6,
elevation: 6
},
backgroundColor && { backgroundColor }
]}
>
<Text style={[styles.appButtonText, size === "sm" && { fontSize: 14 }]}>
{title}
</Text>
</TouchableOpacity>
)
};
const styles = StyleSheet.create({
screenContainer: {
flex: 1,
justifyContent: "center",
padding: 16
},
appButtonContainer: {
elevation: 8,
backgroundColor: "#009688",
borderRadius: 10,
paddingVertical: 10,
paddingHorizontal: 12
},
appButtonText: {
fontSize: 18,
color: "#fff",
fontWeight: "bold",
alignSelf: "center",
textTransform: "uppercase"
}
});
Here is my Background:
import React from 'react'
import { ImageBackground, StyleSheet, KeyboardAvoidingView } from 'react-native'
import { theme } from '../core/theme'
export default function Background({ children }) {
return (
<ImageBackground style={styles.background}>
<KeyboardAvoidingView style={styles.container} behavior="padding">
{children}
</KeyboardAvoidingView>
</ImageBackground>
)
}
const styles = StyleSheet.create({
background: {
flex: 1,
width: '100%',
backgroundColor: theme.colors.surface,
},
container: {
flex: 1,
padding: 20,
width: '100%',
maxWidth: 340,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
},
})
When I try to run the application in my Android phone I get the following error:
Error: Text strings must be rendered within a component.
Blockquote
But I cant figure out where this error happens. Can someone spot the mistake?
You have an unnecessary semicolon (;) in your StartScreen JSX, remove it.
export default function StartScreen({ navigation }) {
return(
<Background>
<AppButton title="HEEEY!" size="sm" backgroundColor="#007bff" />
</Background>
); }

Increase size in React native animated

This is an example code as I'm trying to learn Animated from react native. If I want to press a button and double the size of this text smoothly, how would I do that? From what I understood I need to add Transform: scale x/y somehow but I'm super confused by this. Thanks
import React, { useRef, useEffect } from 'react';
import { Animated, Text, View } from 'react-native';
const FadeInView = (props) => {
const fadeAnim = useRef(new Animated.Value(0)).current
useEffect(() => {
Animated.timing(
fadeAnim,
{
toValue: 1,
duration: 2000,
useNativeDriver: true
}
).start();
}, [])
return (
<Animated.View style={{...props.style, opacity: fadeAnim}}>
{props.children}
</Animated.View>
);
}
export default () => {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<FadeInView>
<Text style={{fontSize: 28, textAlign: 'center', padding: 10}}>Fading in</Text>
</FadeInView>
</View>
)
}
Let's say you want to scale the text when it's clicked. You can do this:
export default () => {
const scaleAnim = useRef(new Animated.Value(1)).current;
const animateTextSize = () => {
Animated.timing(
scaleAnim,
{
toValue: 2,
duration: 2000,
useNativeDriver: true
}
).start();
}
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<FadeInView>
<Animated.Text style={{fontSize: 28, textAlign: 'center', padding: 10, transform:[{scale:scaleAnim}]}} onPress={animateTextSize}>Fading in</Animated.Text>
</FadeInView>
</View>
)}
snack demo

Navigating among three screens

I am about to making an app with React Native and I have three screens with deferent styles (themes). I want to navigate among these three screens, So I am passing data from my main screen (App.js) as parent to the other three as child (screen1, screen2, screen3). I used a modal which has three button in it and i want whenever I pressed one of them, the screen change to the pressed one. This is my App.js file
import React, { useState, useEffect } from "react";
import { StyleSheet, View } from "react-native";
import Screen1 from "./screens/CalcScreen";
import Screen2 from "./screens/Screen1";
import Screen3 from "./screens/Screen2";
export default function App() {
const [whiteScreen, setWhiteScreen] = useState(false);
const [darkScreen, setDarkScreen] = useState(false);
const [pinkScreen, setPinkScreen] = useState(false);
const whiteScreenHandler = () => {
setWhiteScreen(true);
setDarkScreen(false);
setPinkScreen(false);
};
const darkScreenHandler = () => {
setDarkScreen(true);
setWhiteScreen(false);
setPinkScreen(false);
};
const pinkScreenHander = () => {
setPinkScreen(true);
setWhiteScreen(false);
setDarkScreen(false);
};
let content = <screen1 setDarkScreen={darkScreenHandler} />;
let content2 = <Screen2 setWhiteScreen={whiteScreenHandler} />;
let content3 = <Screen3 setPinkScreen={pinkScreenHander} />;
if (darkScreen) {
content = content;
} else if (whiteScreen) {
content = content2;
} else if (pinkScreen) {
content = content3;
}
return <View style={styles.container}>{content}</View>;
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#374351",
},
});
And this is one of my screens and my modals in my screens, the other two screens are same in coding but not in styles and I used this modal in each three screens,(does it right to use in three screens?) anyway whenever I'm pressing modal's button to change the screens i got props.screen handler() is not a function. What is wrong in my code?
import React, { useState } from "react";
import {
StyleSheet,
Text,
ScrollView,
View,
TouchableOpacity,
Alert,
Animated,
Modal,
Pressable,
} from "react-native";
const Screen1 = (props) => {
return (
<View style={styles.screen}>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<View style={styles.button}></View>
<Text style={styles.modalText}>Themes</Text>
<TouchableOpacity
style={styles.darkTheme}
onPress={() => {
props.setDarkScreen();
}}
>
<Text>Dark</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.whiteTheme}
onPress={() => {
props.setWhiteScreen();
}}
>
<Text>White</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.pinkTheme}
onPress={() => {
props.setPinkScreen();
}}
>
<Text>Pink</Text>
</TouchableOpacity>
<Pressable
style={[styles.buttonClose]}
onPress={() => setModalVisible(!modalVisible)}
>
<Text style={styles.textStyle}>X</Text>
</Pressable>
</View>
</View>
</Modal>
<Pressable
style={[styles.button, styles.buttonOpen]}
onPress={() => setModalVisible(true)}
>
<Text style={styles.openText}>{">"}</Text>
</Pressable>
</View>
)
}
const styles = StyleSheet.create({
screen: {
backgroundColor: "#fafcff",
},
centeredView: {
// flex: 1,
marginStart: 15,
justifyContent: "center",
alignItems: "center",
// marginTop: 70,
},
modalView: {
marginTop: 200,
backgroundColor: "rgba(255,255,255,0.5)",
borderRadius: 20,
padding: 20,
alignItems: "center",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.5,
shadowRadius: 4,
elevation: 5,
},
button: {
borderRadius: 15,
padding: 10,
elevation: 2,
justifyContent: "center",
alignItems: "center",
marginTop: 20,
},
buttonOpen: {
backgroundColor: "rgba(1,143,132,0.6)",
position: "absolute",
marginTop: 45,
marginStart: -25,
elevation: 2,
height: 70,
width: 40,
},
buttonClose: {
backgroundColor: "rgba(1,1,1,1)",
height: 40,
width: 40,
borderRadius: 50,
// padding: 10,
elevation: 2,
justifyContent: "center",
alignItems: "center",
marginTop: 20,
},
textStyle: {
color: "white",
// fontWeight: "bold",
textAlign: "center",
},
modalText: {
marginBottom: 10,
textAlign: "center",
},
openText: {
fontSize: 25,
fontWeight: "bold",
color: "white",
textAlign: "right",
},
});
export default Screen1;
You can easily doing that by using "React Native Navigation". Here is the documentation:
https://reactnavigation.org/docs/getting-started. I also recommend you that you might want to create your screens into different files to make your code cleaner.

Why is my style not applied to my child component?

Good evening,
I have been trying to create custom card Component in react native that i can use everywhere i need it.
I apply a part of the style inside the component itself, and for the width, layout etc, where i need it. Then i am trying to use the spread operator to "merge" all the properties in the style of the child component. I saw it in a video tutorial, but it's not working for me, and i don't see what is wrong in my code :
import React from 'react';
import { View, Text, StyleSheet, TextInput, Button } from 'react-native';
import Card from '../components/Card';
import Color from '../constants/colors'
import Input from '../components/Input'
const StartGameScreen = props => {
return (
<View style={styles.screen}>
<Text style={styles.title}>Start a New Game!</Text>
<Card style={styles.inputContainer}>
<Text>Select a Number</Text>
<Input />
<View style={styles.buttonContainer}>
<Button title="Reset" color={Color.accent} onPress={() => {}} />
<Button title="Confirm" color={Color.primary} onPress={() => {}} />
</View>
</Card>
</View>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
padding: 10,
alignItems: 'center'
},
title: {
fontSize: 20,
marginVertical: 10
},
inputContainer: {
width: 300,
maxWidth: '80%',
alignItems: 'center',
},
buttonContainer: {
flexDirection: 'row',
width: '100%',
justifyContent: 'space-between',
paddingHorizontal: 15
},
input: {
width: 50
}
});
export default StartGameScreen;
And the child component :
import React from 'react';
import { View, StyleSheet } from 'react-native';
const Card = props => {
return (
<View style={{ ...styles.card, ...props.style }}> {props.children}</View>
);
};
const styles = StyleSheet.create({
card: {
shadowColor: 'black',
shadowOffset: { width: 0, height: 2 },
shadowRadius: 6,
shadowOpacity: 0.26,
elevation: 8,
backgroundColor: 'white',
padding: 20,
borderRadius: 10
}
});
export default Card;
Note : I tried with input and card, it's working for none of them.
Is that something that we were able to do but we can't anymore ?
Thank you
Have a nice weekend
Try this:
const Card = props => {
return (
<View style={[styles.card, props.style ]}> {props.children}</View>
);
};

Error with invariant violation: Maximum update depth exceeded

I am a beginner in react native and I am trying to make a quiz app by using states and functions to check if the button pressed is the correct option based on the word given. However, I have received this error about invariant violation: Maximum update depth exceeded, could this be due to the way I use onPress?
import React, {Component} from 'react';
import {
View,
Text,
SafeAreaView,
TouchableOpacity,
Image,
ScrollView,
StyleSheet,
} from 'react-native';
import {color} from 'react-native-reanimated';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {createAppContainer} from 'react-navigation';
import {createBottomTabNavigator} from 'react-navigation-tabs';
import {createStackNavigator} from 'react-navigation-stack';
const styles = StyleSheet.create({
progressbar: {
width: 218,
height: 24,
borderRadius: 12,
borderColor: 'grey',
borderWidth: 1,
marginTop: 70,
paddingRight: 79,
paddingLeft: 79,
},
words: {
fontFamily: 'Arial',
fontSize: 85,
fontWeight: 'bold',
},
image: {width: 345, height: 391, borderRadius: 50, marginTop: 31},
button: {width: 100, height: 80, borderRadius: 29, marginHorizontal: 5},
});
export default class quizC extends React.Component {
state = {
progress: 0,
progressbar: 0,
progressbarwidth: 0,
words: '',
imagesource: '',
option: 0,
option1: '',
option2: '',
option3: '',
correctoption: 0,
score: 0,
};
_updateProgress() {
switch (this.state.imagesource) {
case 1:
this.setState({words: 'c_t'});
this.setState({progressbarwidth: 109});
this.setState({correctoption: 2});
this.setState({option1: 'c'});
this.setState({option2: 'a'});
this.setState({option3: 't'});
//return cat
break;
case 2:
this.setState({words: 'do_'});
this.setState({progressbarwidth: 218});
this.setState({correctoption: 3});
this.setState({option1: 'd'});
this.setState({option2: 'o'});
this.setState({option3: 'g'});
//return dog
break;
}
}
_checkcorrectans() {
if (this.state.option == this.state.correctoption) {
this.setState(prevState => ({progress: prevState.progress + 1}));
this.setState(prevState => ({score: prevState.score + 1}));
this.setState({imagesource: this.state.progress});
} else {
this.setState(prevState => ({progress: prevState.progress + 1}));
this.setState({imagesource: this.state.progress});
}
}
option1() {
this.setState({option: 1});
this._checkcorrectans();
this._updateProgress();
}
option2() {
this.setState({option: 2});
this._checkcorrectans();
this._updateProgress();
}
option3() {
this.setState({option: 3});
this._checkcorrectans();
this._updateProgress();
}
render() {
return (
<SafeAreaView>
<View style={styles.progressbar}>
<View
style={{
height: 24,
borderRadius: 12,
backgroundColor: 'green',
width: this.state.progressbarwidth,
}}
/>
</View>
<View style={{alignItems: 'center', marginTop: 12}}>
<Text style={styles.words}>{this.state.words}</Text>
</View>
<View style={styles.image}>
<Image src={this._updateProgress()} />
</View>
<View style={{paddingLeft: 23, paddingRight: 23, flexDirection: 'row'}}>
<TouchableOpacity onPress={this.option1()}>
<View style={styles.button}>
<Text>{this.state.option1}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this.option2()}>
<View style={styles.button}>
<Text>{this.state.option2}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this.option3()}>
<View style={styles.button}>
<Text>{this.state.option3}</Text>
</View>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
}
Try using
onPress={() => this.option1()} which is an anonymous function first and the calls option1 or onPress={ this.option1} . These will prevent re-rendering.
This error is due to when you call onPress={this.option1()} , it calls the function and causes the app to re-render which again causes function to be invoked, and hence an infinite loop. The best way would be calling it directly without parentheses onPress={this.option1} or create an anonymous function onPress={() => this.option1()}, which gets executed only once
hope it helps. feel free for doubts
Replace all of onPress method
from:
onPress={this.option1()}
To :
onPress={() => this.option1()}