Unable to clear setInterval in react native app - javascript

I have this very simple app, where I am trying to implement countdown, Start and Stop functionality seems to be working fine but when I press Stop, the value of seconds is not updating in the view which is desired behaviour but when I observed console log, it it showing the value of sec continuously changing which I guess shows that setInterval is still running and not cleared.
Here is the accompanied code:
import React, { useState, useEffect } from "react";
import {
StyleSheet,
Text,
View,
StatusBar,
TouchableOpacity,
Dimensions,
} from "react-native";
const screen = Dimensions.get("screen");
export default function App() {
const [seconds, setSeconds] = useState(4);
const [start, setStartToggle] = useState(true);
let [fun, setFun] = useState(null);
const getRemaining = () => {
const minute = Math.floor(seconds / 60);
const second = seconds - minute * 60;
return formatTime(minute) + ":" + formatTime(second);
};
const formatTime = (time) => {
return ("0" + time).slice(-2);
};
const startTimer = () => {
setStartToggle(false);
console.log("StartTimer");
let sec = seconds;
setFun(
setInterval(() => {
console.log("akak:", sec);
if (sec <= 0) stopTimer();
setSeconds(sec--);
}, 1000)
);
};
const stopTimer = () => {
setStartToggle(true);
console.log("StopTimer");
clearInterval(fun);
setFun(null);
};
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<Text style={styles.timerText}>{getRemaining(seconds)}</Text>
{start ? (
<TouchableOpacity onPress={startTimer} style={styles.button}>
<Text style={styles.buttonText}>Start</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
onPress={stopTimer}
style={[styles.button, { borderColor: "orange" }]}
>
<Text style={styles.buttonText}>Stop</Text>
</TouchableOpacity>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#07121B",
alignItems: "center",
justifyContent: "center",
},
button: {
borderWidth: 10,
borderColor: "#89aaff",
width: screen.width / 2,
height: screen.width / 2,
borderRadius: screen.width / 2,
justifyContent: "center",
alignItems: "center",
},
buttonText: {
fontSize: 40,
color: "#89aaff",
fontWeight: "bold",
},
timerText: {
fontSize: 90,
color: "#89aaff",
fontWeight: "bold",
marginBottom: 20,
},
});
App Behaviour:
Output being shown even after Stop is hit:
Thanks to Emiel Zuurbier and lissettdm for their answers, my code is working now.
Working code:
// import { StatusBar } from "expo-status-bar";
import React, { useState, useEffect, useRef } from "react";
import {
StyleSheet,
Text,
View,
StatusBar,
TouchableOpacity,
Dimensions,
} from "react-native";
const screen = Dimensions.get("screen");
export default function App() {
const [seconds, setSeconds] = useState(11);
const funRef = useRef(null);
const [start, setStartToggle] = useState(true);
const getRemaining = () => {
const minute = Math.floor(seconds / 60);
const second = seconds - minute * 60;
return formatTime(minute) + ":" + formatTime(second);
};
const formatTime = (time) => {
return ("0" + time).slice(-2);
};
let sec = seconds;
useEffect(() => {
// let timer = null;
if (!start) {
let sec = seconds;
funRef.current = setInterval(() => {
console.log("Seconds remaining:", sec);
if (sec <= 0) {
clearInterval(funRef.current);
setStartToggle(true);
}
setSeconds(sec--);
}, 1000);
} else {
clearInterval(funRef.current);
}
}, [start]);
const startTimer = () => {
setSeconds(sec);
setStartToggle(false);
};
const stopTimer = () => {
setSeconds(sec);
setStartToggle(true);
};
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<Text
style={
seconds ? styles.timerText : [styles.timerText, { color: "red" }]
}
>
{getRemaining(seconds)}
</Text>
{start ? (
<TouchableOpacity onPress={startTimer} style={styles.button}>
<Text style={styles.buttonText}>Start</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
onPress={stopTimer}
style={[styles.button, { borderColor: "orange" }]}
>
<Text style={styles.buttonText}>Stop</Text>
</TouchableOpacity>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#07121B",
alignItems: "center",
justifyContent: "center",
},
button: {
borderWidth: 10,
borderColor: "#89aaff",
width: screen.width / 2,
height: screen.width / 2,
borderRadius: screen.width / 2,
justifyContent: "center",
alignItems: "center",
},
buttonText: {
fontSize: 40,
color: "#89aaff",
fontWeight: "bold",
},
timerText: {
fontSize: 90,
color: "#89aaff",
fontWeight: "bold",
marginBottom: 20,
},
});

Currently you use the useState hook to store the interval reference. At every re-render of the App component the fun state is reset, but will not be the exact same reference to the interval.
Instead use the useRef hook. It can create a reference to the interval which will not change during re-renders. This means that the value in the current property of the reference will always be the exact same one.
To top it off, use the useEffect hook to watch when a running state is set or unset and start and stop the timer based on that state.
import React, { useState, useRef, useEffect } from 'react'
export default function App() {
const [isRunning, setIsRunning] = useState(false);
const funRef = useRef(null);
const startTimer = () => {
if (!isRunning) {
setIsRunning(true);
}
};
const stopTimer = () {
if (isRunning && funRef.current !== null) {
setIsRunning(false);
}
};
useEffect(() => {
if (isRunning) {
funRef.current = setInterval(() => { // Save reference to interval.
// ...
}, 1000);
} else {
clearInterval(funRef.current); // Stop the interval.
}
}, [isRunning]);
// ...
}

Add interval timer inside useEffect block, and run this block every time start changes:
useEffect(()=> {
let timer = null;
if(!start) {
let sec = seconds;
timer = setInterval(() => {
console.log("akak:", sec);
if (sec <= 0) clearInterval(timer);
setSeconds(sec--);
}, 1000);
} else {
clearInterval(timer);
}
}, [start]);
const startTimer = () => {
setStartToggle(false);
};
const stopTimer = () => {
setStartToggle(true);
};
Also, I recommend you to use the exact remaining time. Javascript is a single threaded language, and this interval could be more than one second
EDIT: using the exact time.
useEffect(() => {
let timer = null;
if (!start) {
let sec = seconds;
const startTime = Date.now();
timer = setInterval(() => {
const currentTime = Date.now();
sec = sec - Math.floor((currentTime - startTime) / 1000);
if (sec < 0) {
clearInterval(timer);
setSeconds(0);
} else {
setSeconds(sec);
}
}, 1000);
}
}, [start]);

Related

Add event to selected day Calendar Agenda

I am currently learning to build an app with react native expo and javascript. I have my calendar displaying but I can't figure out how to add event to day selected. There will be a button that the user press and from this they should be able to add events to that day. This was the guide used to build the agenda https://github.com/wix/react-native-calendars/blob/master/example/src/screens/agendaScreen.tsx
import React, { Component, useState } from "react";
import { Alert, StyleSheet, Text, View, TouchableOpacity } from "react-native";
import {
Agenda,
DateData,
AgendaEntry,
AgendaSchedule,
} from "react-native-calendars";
import { Card } from "react-native-paper";
const timeToString = (time) => {
const date = new Date(time);
return date.toISOString().split("T")[0];
};
const CalendarComponent = () => {
const [entree, setItems] = useState({});
const loadItems = (day) => {
setTimeout(() => {
for (let i = -15; i < 85; i++) {
const time = day.timestamp + i * 24 * 60 * 60 * 1000;
const strTime = timeToString(time);
if (!entree[strTime]) {
entree[strTime] = [];
}
}
const newItems = {};
Object.keys(entree).forEach((key) => {
newItems[key] = entree[key];
});
setItems(newItems);
}, 1000);
};
const renderEmptyDate = () => {
return (
<View style={styles.emptyDate}>
<Text>This is empty date!</Text>
</View>
);
};
const renderItem = (item) => {
return (
<TouchableOpacity style={styles.item}>
<Card>
<Card.Content>
<View>
<Text>{item.name}</Text>
</View>
</Card.Content>
</Card>
</TouchableOpacity>
);
};
return (
<Agenda
items={entree}
loadItemsForMonth={loadItems}
renderItem={renderItem}
renderEmptyDate={renderEmptyDate}
showClosingKnob={true}
/>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: "white",
flex: 1,
borderRadius: 5,
padding: 10,
marginRight: 10,
marginTop: 17,
},
emptyDate: {
height: 15,
flex: 1,
paddingTop: 30,
},
});
export default CalendarComponent;

I want to restart a circular progress bar after 30 seconds

const useProgress = (maxTimeInSeconds = 30) => {
const [elapsedTime, setElapsedTime] = useState(0);
const [progress, setProgress] = useState(0);
useEffect(() => {
const intervalId = setInterval((callback) => {
if (progress < 1) {
setElapsedTime((t) => t + 1);
}
}, 1000);
return () => clearInterval(intervalId);
}, []);
useEffect(() => {
setProgress(elapsedTime / maxTimeInSeconds);
console.log(elapsedTime);
}, [elapsedTime]);
return progress;
};
const progress = useProgress();
Here I have implemented logic to move the circular progress bar for 30 seconds. What I want to do is restart the progress after 30 seconds and keep it in the loop for 30 seconds.
here I have pasted the whole code
import { Observer } from "mobx-react";
import React, { Component, useEffect, useState } from "react";
import {
StyleSheet,
Text,
View,
ImageBackground,
TouchableOpacity,
Image,
Platform,
Dimensions,
Clipboard,
} from "react-native";
import * as Progress from "react-native-progress";
import AppStore from "../../stores/AppStore";
import Iconpack from "../../utils/Iconpack";
import Theme from "../../utils/Theme";
import DeviceInfo from "react-native-device-info";
import CircularProgressBar from "./CircularProgressBar";
import { Shadow } from "react-native-shadow-2";
import Toast from "react-native-simple-toast";
import { BoxShadow } from "react-native-shadow";
import FastImage from "react-native-fast-image";
// import Clipboard from "#react-native-community/clipboard";
const hRem = AppStore.screenHeight / 812;
const wRem = AppStore.screenWidth / 375;
const OtpDetails = ({ route, params, navigation }) => {
const { id, title } = route.params;
const useProgress = (maxTimeInSeconds = 30) => {
const [elapsedTime, setElapsedTime] = useState(0);
const [progress, setProgress] = useState(0);
useEffect(() => {
const intervalId = setInterval((callback) => {
if (progress < 1) {
setElapsedTime((t) => t + 1);
}
}, 1000);
return () => clearInterval(intervalId);
}, []);
useEffect(() => {
console.log(elapsedTime);
setProgress(elapsedTime / maxTimeInSeconds);
if (elapsedTime == 30) {
setProgress(elapsedTime / maxTimeInSeconds);
}
}, [elapsedTime / maxTimeInSeconds]);
return progress;
};
const progress = useProgress();
const setTextIntoClipboard = async () => {
await Clipboard.setString(title);
Toast.show("OTP copied successfully!", 200);
};
const deviceName = DeviceInfo.getModel();
return (
<Observer>
{() => (
<View style={{ flex: 1 }}>
<FastImage
style={styles.container}
source={Iconpack.GLOBAL_BG}
resizeMode={FastImage.resizeMode.cover}
/>
<View style={styles.headerStyle}>
<TouchableOpacity
onPress={() => {
navigation.navigate("OtpScreen");
}}
>
<Image
style={styles.backButton}
source={Iconpack.GLOBAL_BACK_BUTTON}
/>
</TouchableOpacity>
<Text style={styles.headerTitle}>{title}</Text>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity>
<Image
style={[styles.editTrashButton, { marginRight: 19 }]}
source={Iconpack.EDIT_ICON}
/>
</TouchableOpacity>
<TouchableOpacity>
<Image
style={styles.editTrashButton}
source={Iconpack.DELETE_ICON}
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.circleOuter}>
{Platform.OS === "ios" ? (
<View style={styles.circleContainer}>
<Progress.Circle
style={{ alignItems: "center" }}
progress={progress}
// indeterminate={this.state.indeterminate}
size={Dimensions.get("window").width * 0.561}
thickness={10}
borderWidth={0}
endAngle={10}
strokeCap="round"
color={"#354659"}
// indeterminateAnimationDuration={1}
unfilledColor={"#031830"}
/>
</View>
) : (
<Shadow
distance={20}
startColor={"rgba(27, 100, 206, 0.5)"}
radius={210}
safeRender={true}
>
<View style={styles.circleContainer}>
<Progress.Circle
style={{ alignItems: "center", overflow: "hidden" }}
progress={progress}
// indeterminate={this.state.indeterminate}
size={Dimensions.get("window").width * 0.561}
thickness={10}
borderWidth={0}
endAngle={10}
strokeCap="round"
color={"#354659"}
indeterminateAnimationDuration={2000}
unfilledColor={"#031830"}
/>
</View>
</Shadow>
)}
<Text style={[styles.circleItem]}>{title}</Text>
<TouchableOpacity
onPress={() => {
setTextIntoClipboard();
}}
style={styles.copyItem}
>
<Text style={styles.copyText}>TAP TO COPY</Text>
</TouchableOpacity>
</View>
{/* <View style={styles.circleOuter}>
<View style={styles.circleContainer}>
<Text style={styles.circleItem}>title</Text>
</View>
<TouchableOpacity
onPress={() => {
copyToClipboard();
}}
style={styles.copyItem}
>
<Text style={styles.copyText}>TAP TO COPY</Text>
</TouchableOpacity> */}
{/* </View> */}
</View>
)}
</Observer>
);
};
export default OtpDetails;
const styles = StyleSheet.create({
container: {
flex: 1,
position: "absolute",
top: 0,
right: 0,
left: 0,
bottom: 0,
backgroundColor: "#021831",
},
headerStyle: {
flexDirection: "row",
marginTop: Platform.OS === "ios" ? 56 : 40,
marginHorizontal: wRem * 26.66,
justifyContent: "space-between",
alignItems: "center",
},
backButton: {
width: wRem * 12,
height: hRem * 21,
},
editTrashButton: {
width: wRem * 23,
height: hRem * 23,
},
headerTitle: {
...Theme.encodeSansMed2,
color: "#FFFFFF",
fontWeight: "600",
marginLeft: wRem * 50,
},
circleOuter: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
circleContainer: {
borderRadius:
Math.round(
Dimensions.get("window").width + Dimensions.get("window").height
) / 2,
width: Dimensions.get("window").width * 0.56,
height: Dimensions.get("window").width * 0.56,
justifyContent: "center",
backgroundColor: "black",
shadowColor: "rgba(27, 100, 206, 0.5)",
shadowOffset: {
width: 0,
height: 0,
},
shadowOpacity: 30,
shadowRadius: 30,
},
circleItem: {
color: "white",
...Theme.encodeSansMed7,
textAlign: "center",
position: "absolute",
width: "100%",
paddingBottom: 100,
},
copyItem: {
justifyContent: "center",
alignItems: "center",
marginTop: hRem * 64,
},
copyText: {
color: "#3D4756",
...Theme.encodeSansMed4,
},
});
with all styling and the most important thing is I am using third party party library react-native-progress thanks
progress does not need to be a state atom since it's always unambiguously calculable from the elapsed time and max time.
Using the modulo (remainder) operator you can have the observed progress always loop back to 0 after the maximum time.
const useProgress = (maxTimeInSeconds = 30) => {
const [elapsedTime, setElapsedTime] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setElapsedTime((t) => t + 1);
}, 1000);
return () => clearInterval(intervalId);
}, []);
return (elapsedTime % maxTimeInSeconds) / maxTimeInSeconds;
};
const progress = useProgress();
Alternately, if you want slightly more accurate, wallclock-based timing:
const useProgress = (maxTimeInSeconds = 30) => {
const [initialTime] = useState(() => +new Date());
const [counter, setCounter] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCounter((t) => t + 1);
}, 1000);
return () => clearInterval(intervalId);
}, []);
const elapsedTime = Math.floor(((+new Date()) - initialTime) / 1000);
if (elapsedTime == 30) {
return maxTimeInSeconds;
}
return (elapsedTime % maxTimeInSeconds) / maxTimeInSeconds;
};
This pins the progress start to the component's mount time, and should work better even when setInterval isn't accurate.

React native refreshControl ScrollView bottom-sheet ios

I am using the following component bottom-sheet, where I am implementing the pull-to-refresh, on android it works perfectly on ios it is not working.
I tried to follow various guides, but I could not figure out what the problem is that on ios it is not working.
Can anyone help me out?
Android ok:
Link: snack
import React, { useCallback, useRef, useMemo, useEffect } from 'react';
import {
StyleSheet,
View,
Text,
Button,
RefreshControl,
ToastAndroid,
Platform,
} from 'react-native';
import BottomSheet, { BottomSheetScrollView } from '#gorhom/bottom-sheet';
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const App = () => {
// hooks
const sheetRef = useRef<BottomSheet>(null);
const [refreshing, setRefreshing] = React.useState(false);
const [listData, setListData] = React.useState([]);
const onRefresh = React.useCallback(async () => {
console.log('Refresh');
setRefreshing(true);
try {
const n = getRandomInt(10, 30);
console.log(n);
let response = await fetch('https://randomuser.me/api/?results=' + n);
let responseJson = await response.json();
setListData(responseJson.results);
setRefreshing(false);
} catch (error) {
console.error(error);
}
}, [refreshing]);
useEffect(() => {
onRefresh();
}, []);
// variables
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
// callbacks
const handleSheetChange = useCallback((index) => {
console.log('handleSheetChange', index);
}, []);
const handleSnapPress = useCallback((index) => {
sheetRef.current?.snapTo(index);
}, []);
const handleClosePress = useCallback(() => {
sheetRef.current?.close();
}, []);
// render
const renderItem = useCallback(
(item) => (
<View key={item.login.uuid} style={styles.itemContainer}>
<Text>{item.email}</Text>
</View>
),
[]
);
return (
<View style={styles.container}>
<BottomSheet
ref={sheetRef}
index={2}
snapPoints={snapPoints}
onChange={handleSheetChange}
enableContentPanningGesture={false}
enableHandlePanningGesture={false}>
<BottomSheetScrollView
contentContainerStyle={{
backgroundColor: 'white',
//paddingTop: Platform.OS === 'ios' ? 0 : 64,
}}
contentInset={{ top: 64 }}
contentOffset={{ x: 0, y: -64 }}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
progressViewOffset={64}
colors={['#000']}
tintColor={'#000'}
/>
}>
{listData.map(renderItem)}
</BottomSheetScrollView>
</BottomSheet>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 200,
},
contentContainer: {
backgroundColor: 'white',
},
itemContainer: {
padding: 6,
margin: 6,
backgroundColor: '#eee',
},
});
export default App;

React useState starts bugging after multiple state changes

Im working on a cookie clicker type game and Im working on making features like automatic clickers / combo multipliers. I created the start of the game but when I use my auto function it begins bugging after multiple clicks of the clicker. I have linked the code and an example of the bug occurring below.
CODE
import React, { useState, useEffect } from "react";
import { StyleSheet, Text, View, Image } from "react-native";
import { cases } from "./cases";
import { motion } from "framer-motion";
const io = require("socket.io-client");
const SocketEndpoint = "http://localhost:3000/";
const App = () => {
const [cash, setCash] = useState(0);
const [clicks, setClicks] = useState(0);
const [bot, setBot] = useState(0);
const [open, setOpen] = useState(false);
const [prize, setPrize] = useState(null);
const [connected, setConnected] = useState(false);
const [upgrades, setUpgrades] = useState({auto: false, multi: false})
const [multi, setMulti] = useState(1);
let applied = false;
useEffect(() => {[![enter image description here][1]][1]
const socket = io(SocketEndpoint, {
transports: ["websocket"],
});
socket.on("connect", () => {
setConnected(true)
});
}, [])
useEffect(() => {
if(!applied) {
autoUpgrade();
applied = true;
}
}, [bot, upgrades])
const autoUpgrade = () => {
if (!upgrades.auto) {
return;
}
const inter = setInterval(() => setBot(bot + 1), 1000);
return () => clearInterval(inter);
}
const collectBotIncome = () => {
setCash(cash + bot);
setBot(0);
}
const addMulti = () => {
if (!upgrades.multi) {
return;
}
setMulti(2)
}
const increasePoint = () => {
setClicks(clicks + (1 * multi))
}
const purchaseCase = () => {
setClicks(clicks - 10)
}
const purchaseUpgrade = (upgrade) => {
alert('purchased')
upgrade === 'auto' ? setUpgrades({...upgrades, auto: true}) : null;
upgrade === 'multi' ? setUpgrades({...upgrades, multi: true}) : null;
}
const between = (x, min, max) => {
return x >= min && x <= max;
}
const openCase = () => {
setOpen(true);
purchaseCase();
const ticket = Math.floor(Math.random() * 10000);
console.log('[ROUND] Ticket:' + ticket)
var found = false;
var i;
for (i = 0; i < cases.types[0].items.length; i++) {
var item = cases.types[0].items[i];
if(between(ticket, item.ticketStart, item.ticketEnd)) {
setPrize(item.name)
found = true;
}
}
}
return (
<View style={styles.container}>
<View style={styles.shopMenu}>
<Text style={{color: 'white'}}>Shop</Text>
<Text onClick={() => purchaseUpgrade('auto')} style={{color: 'white'}}>Auto Click Level 1</Text>
<Text onClick={() => purchaseUpgrade('multi')} style={{color: 'white'}}>Click Multiplier Level 1</Text>
</View>
<View style={styles.shopMenu}>
<Text style={{color: 'white'}}>Inventory</Text>
{upgrades.auto
?
<>
<Text style={{color: 'white'}}>{bot}</Text>
<Text onClick={collectBotIncome} style={{color: 'white'}}>Collect Bot Income</Text>
</>
: null
}
</View>
<motion.img
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
onClick={increasePoint}
src={require('./src/assets/case.png')} alt="case"
/>
<Text style={{color: 'white'}}>clicks: {clicks ? clicks : "0"}</Text>
<Text style={{color: 'white'}}>connected: {connected ? "true" : "false"}</Text>
{open
? <Text style={{color: 'white'}}>{prize ? prize : 'Failed to get Prize'}</Text>
: <Image
style={clicks >= 10 ? styles.available : styles.unavailable}
source={require('./src/assets/case.png')} alt="case"
onClick={openCase}
/>
}
<Text style={{color: 'white'}}>{cases.types[0].name}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "black",
alignItems: "center",
justifyContent: "center",
},
available: {
display: 'flex',
width: 150,
height: 100,
filter: 'none',
transition: '200ms ease',
marginTop: 50
},
unavailable: {
display: "flex",
width: 150,
height: 100,
filter: 'grayscale(1)',
transition: '200ms ease',
marginTop: 50
},
shopMenu: {
display: "flex",
flexDirection: "column"
}
});
export default App;
PREVIEW

How do i loop animated-circular-progress component

I'm using the react-native-circular-progress component and I'm trying to loop an animation every 30 seconds.
i.e the animation is 30 seconds long and i want it to restart as soon as its done
The component exposes a function named reAnimate which I have put in a setInterval function as soon as the component mounts.
import React from 'react';
import { StyleSheet, Text, View,Dimensions, Easing } from 'react-native';
import { AnimatedCircularProgress } from 'react-native-circular-progress';
const MAX_POINTS = 30;
export default class App extends React.Component {
state = {
isMoving: false,
pointsDelta: 0,
points: 1,
};
componentDidMount(){
setInterval(
() => this.circularProgress.reAnimate(0,100, 30000,Easing.linear),
30000
);
}
render() {
const { width } = Dimensions.get("window");
const window = width - 120;
const fill = (this.state.points / MAX_POINTS) * 100;
return (
<View style={styles.container} >
<AnimatedCircularProgress
size={window}
width={7}
backgroundWidth={5}
fill={0}
tintColor="#ef9837"
backgroundColor="#3d5875"
ref={(ref) => this.circularProgress = ref}
arcSweepAngle={240}
rotation={240}
lineCap="round"
>
{fill => <Text style={styles.points}>{Math.round((MAX_POINTS * fill) / 100)}</Text>}
</AnimatedCircularProgress>
</View>
);
}
}
const styles = StyleSheet.create({
points: {
textAlign: 'center',
color: '#ef9837',
fontSize: 50,
fontWeight: '100',
},
container: {
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: '#0d131d',
padding: 50,
},
pointsDelta: {
color: '#4c6479',
fontSize: 50,
fontWeight: '100',
},
pointsDeltaActive: {
color: '#fff',
},
});
This is working... BUT... the animation only starts 30s after the component mounts. How do i get it to loop immediately?
Any help will be greatly appreciated.
Thank you.
The reason is setInterval will not fire immediately it will start after the duration you passed i.e 30 mins, So all you have to do is make a call initially before setting the interval, also don't forget to clear the interval.
Here's how I would it:
componentDidMount(){
this.circularProgress.animate(100, 30000,Easing.linear);
this.intervalId = setInterval(
() => this.circularProgress.reAnimate(0,100, 30000,Easing.linear),
30000
);
}
componentWillUnmount() {
clearInterval(this.intervalId);
}

Categories

Resources