so im working on making a timer count down from some given amount of time which is determined by a slider.
then one can click a start button starting at the slider's value, and begin the count down.
(as it is though, im just working with set values, which I will then somehow link up this slider)
ive been working around this setinterval() func just to see if I can make it count down from 60. but after a few seconds it starts to count radically. i think it has to do with my lack of understanding of state and the way it renders the state repeatedly, or something.
---just learning so bear with the irationality of this code, criticism is apprecieated!---
export const Timer = ({navigation}) => {
const [minutes, setMin] = useState(30);
const [seconds, setSeconds] = useState(60);
let value = 30;
const handleSliderChange = (value) => {
setMin(value)
}
function minusSecond() {
setSeconds(seconds- 1)
}
return(
<View style={styles.Timer}>
<Text style={styles.Txt2}>M I N U T E S</Text>
<View style={styles.Slider}>
<Slider
style={{width: 300, height:40}}
minimumValue={5}
maximumValue={120}
value={value}
step={5}
thumbTintColor='white'
minimumTrackTintColor="#FFFFFF"
maximumTrackTintColor="#000000"
onValueChange={handleSliderChange}
/>
</View>
<View>
<Text style={styles.Time}>
{minutes}:{seconds}
</Text>
</View>
<View style={styles.Start}>
<TouchableOpacity style={styles.buttonStyle} title="Start" onPress={setInterval(setSeconds, 1000)}}>
<Text style={styles.ButtonTxt}>START</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.buttonStyle } title="Home Page">
<Text style={styles.ButtonTxt}>STOP</Text>
</TouchableOpacity>
</View>
</View>
)
}
Your countdown timer logic should look something like this:
const [countDown, setCountDown] = React.useState(60);
const [startTimer, setTimer] = React.useState(false);
React.useEffect(() => {
let timer = setInterval(() => {
if (startTimer) {
setCountDown(countDown > 0 ? countDown - 1 : 0);
}
}, 1000);
return () => {
clearInterval(timer);
};
}, [countDown, startTimer]);
const resetCountDown = () => {
setCountDown(60);
};
Check out the example project below for a live demo.
https://snack.expo.io/#bapeter01/countdown-example
Related
I'm creating a simple text-to-speech function for my react native app.
I have a button, when you click it for the first time, it will read the text and play the sound.
But I want to make it dynamic. For example: If you click again it should stop, if click again, should play again, etc.....
But now, it is only available for playing the sound with any click.
Where/how should I execute the stopReadText()?
I still don't have any idea about this. Thanks a lot.
Here is the code:
const readText = () => {
Speech.speak('text')
}
const stopReadText = () => {
Speech.stop()
}
return (
<View>
<TouchableOpacity onPress=(readText)>
<Divider style={styles.modalDivider} />
<Image
style={styles.speaker}
source={require('../../assets/speaker.png')}
/>
</TouchableOpacity>
</View>
)
(I am using expo-speech)
You can do it by taking on a boolean state variable:
import { useState } from 'react';
const [isPlay,setIsPlay]=useState(false)
const readText = () => {
Speech.speak('text')
}
const stopReadText = () => {
Speech.stop()
}
const handlePlay =() =>{
if(!setIsPlay){
readText()
setIsPlay(true)
}
else {
stopReadText()
setIsPlay(false)
}
}
return (
<View>
<TouchableOpacity onPress={handlePlay}>
<Divider style={styles.modalDivider} />
<Image
style={styles.speaker}
source={require('../../assets/speaker.png')}
/>
</TouchableOpacity>
</View>
)
is it possible, in a React Native Function, to render the "return" at changes?
What I try:
I have a Function - this Function gets an specific array out of another Function - on Button Press I generate a new Index - now what I want is to re-render the View to display the array element with the new Index:
const generateNewIndex = function (item) {
return Math.floor(Math.random() * item.length);
};
const PositionItem = ({ arr, position, navigation }) => {
let { name, beschreibung, arten, rooms, isStarred } = position;
let testArray = arr;
let i = 0;
return (
<View style={styles.posContainer}>
<View style={styles.titles}>
<Text style={styles.title}>{name}</Text>
<Text style={styles.subtitle}>{beschreibung}</Text>
<Text style={styles.title}>{testArray[i].name}</Text>
</View>
<View style={styles.buttonsContainer}>
<StyledButton
type="primary"
content={"Next Random Position"}
onPress={() => {
console.warn("Pressed");
i = generateNewIndex(testArray);
}}
/>
</View>
</View>
);
};
export default PositionItem;
Thanks in advance!
I have found a way which is Working.
If anyone wonders in the Future what I did:
add a Use State component:
const [count, setCount] = useState(0);
onPress on Button increase the Count:
onPress={() => {
i = generateNewIndex(array);
setCount((prevCount) => prevCount + 1);
}}
I'm using the Pressable React Native component for items displayed in a FlatList.
I want to be able to scroll back and forth through the list and have no feedback from the items, unless pressed for a a little while.
The onPress function invoked can easily be delayed with the onLongPress capability, however I also want to invoke an opacity over the item after it's been pressed for a little while, NOT during scrolling. There doesn't seem to be an easy way to do this. What I've tried so far without succes:
.........
const sleep = (milliseconds: any) => {
return new Promise(resolve => setTimeout(resolve, milliseconds));
};
const display = (pressed: boolean) => {
if (pressed) {
sleep(3000).then(() => {
return true;
});
}
return false;
};
const ItemInList: FunctionComponent<ItemInListProps> = ({
style,
colors,
title = '',
text,
subtext,
children,
onPress,
}) => {
return (
<Pressable
onLongPress={onPress}
delayLongPress={3000}
style={({ pressed }) => [
{
opacity: display(pressed) ? 0.2 : 1,
},
]}>
<LinearGradient
colors={colors || []}
style={StyleSheet.flatten([styles.container, style])}>
<View style={styles.titleContainer}>
<Text style={styles.titleStyle}>{title}</Text>
</View>
<View style={subtext ? styles.subtextContainer : styles.textContainer}>
<Text style={styles.textStyle}>{text}</Text>
</View>
{subtext && (
<View style={styles.subtextContainer}>
<Text style={styles.subtextStyle}>{subtext}</Text>
</View>
)}
{children}
</LinearGradient>
</Pressable>
);
};
export default ItemInList;
This has no effect whatsoever, opacity is never displayed.
Does anyone have a good idea about how to handle this?
Thanks.
Can you try TouchableOpacity? it has props delayPressIn and many props u can try these
I'm pretty sure that when the OP has asked this question, there was no straightforward solution.
Right now you can use the "unstable_pressDelay" provided prop to define a number of milliseconds to delay the pressable activation.
Example code:
<Pressable
unstable_pressDelay={5000}
onPress={() => {
setTimesPressed((current) => current + 1);
}}
style={({ pressed }) => [
{
backgroundColor: pressed
? 'rgb(210, 230, 255)'
: 'white'
},
styles.wrapperCustom
]}>
{({ pressed }) => (
<Text style={styles.text}>
{pressed ? 'Pressed!' : 'Press Me'}
</Text>
)}
</Pressable>
Documentation: https://reactnative.dev/docs/pressable#unstable_pressdelay
I am using react-native-camera for the first time and I am using functional component for that. I want to open the camera on button click but using the ref is not working. Here is my code :
const camContainer = () => {
const cameraRef = useRef(null);
useEffect(() => {
console.log(cameraRef);
}, [cameraRef]);
const openCamera = () => {
const options = {quality: 0.5, base64: true};
// cameraRef.current.takePictureAsync(options);
console.log(cameraRef);
};
return (
<TouchableOpacity onPress={() => openCamera()}>
<Text>Open Camera</Text>
{!cameraRef && (
<View>
<RNCamera ref={cameraRef} style={{flex: 1, alignItems: 'center'}} />
</View>
)}
</TouchableOpacity>
);
};
I logged cameraRef using useEffect but the cameraRef.current was still null, I cannot understand how do I open the camera then ?
in docs of RNCamera, it should be like this
<Camera
ref={ref => {
this.camera = ref;
}}
/>;
// ...
snap = async () => {
if (this.camera) {
let photo = await this.camera.takePictureAsync();
}
};
So I'm trying to attach a .on listener, like so
firebase.database().ref('Users').child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').on('value', snap => {
const user = snap.val();
alert(true);
}).catch(e => alert(e))
The problem is, I get an error saying
Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info. (Saw setTimeout with duration 398331ms)
which I guess makes sense. The only solutions I could find were to just hide the warning, which sounds like a bad idea. Especially that my app started freezing after a while when I added this listener.
I know there is react-native-firebase available, but I've read all it does, is just hide the warning, not really solving the problem.
How can this problem be solved though? Or does it just have to be like this on Android?
Entire home class
export default class HomeScreen extends React.Component {
static navigationOptions = {
header: null,
};
componentWillMount() {
(async () => {
await firebase.auth().signInAndRetrieveDataWithEmailAndPassword('loigin', 'pass');
const val = await firebase.database().ref('Users').child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').once('value').then(r => r.val()).catch(e => alert(e));
alert(val);
})();
}
render() {
// firebase.database().ref('Users').child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').on('value', snap => {
// const user = snap.val();
// alert(true);
// }).catch(e => alert(e))
alert(false)
return (
<View style={styles.container}>
<ScrollView style={styles.container} contentContainerStyle={styles.contentContainer}>
<View style={styles.welcomeContainer}>
<Image
source={
__DEV__
? require('../assets/images/robot-dev.png')
: require('../assets/images/robot-prod.png')
}
style={styles.welcomeImage}
/>
</View>
<View style={styles.getStartedContainer}>
{this._maybeRenderDevelopmentModeWarning()}
<Text style={styles.getStartedText}>Get started by opening</Text>
<View style={[styles.codeHighlightContainer, styles.homeScreenFilename]}>
<MonoText style={styles.codeHighlightText}>screens/HomeScreen.js</MonoText>
</View>
<Text style={styles.getStartedText}>
Change this text and your app will automatically reload.
</Text>
</View>
<View style={styles.helpContainer}>
<TouchableOpacity onPress={this._handleHelpPress} style={styles.helpLink}>
<Text style={styles.helpLinkText}>Help, it didn’t automatically reload!</Text>
</TouchableOpacity>
</View>
</ScrollView>
<View style={styles.tabBarInfoContainer}>
<Text style={styles.tabBarInfoText}>This is a tab bar. You can edit it in:</Text>
<View style={[styles.codeHighlightContainer, styles.navigationFilename]}>
<MonoText style={styles.codeHighlightText}>navigation/MainTabNavigator.js</MonoText>
</View>
</View>
</View>
);
}
_maybeRenderDevelopmentModeWarning() {
if (__DEV__) {
const learnMoreButton = (
<Text onPress={this._handleLearnMorePress} style={styles.helpLinkText}>
Learn more
</Text>
);
return (
<Text style={styles.developmentModeText}>
Development mode is enabled, your app will be slower but you can use useful development
tools. {learnMoreButton}
</Text>
);
} else {
return (
<Text style={styles.developmentModeText}>
You are not in development mode, your app will run at full speed.
</Text>
);
}
}
_handleLearnMorePress = () => {
WebBrowser.openBrowserAsync('https://docs.expo.io/versions/latest/guides/development-mode');
};
_handleHelpPress = () => {
WebBrowser.openBrowserAsync(
'https://docs.expo.io/versions/latest/guides/up-and-running.html#can-t-see-your-changes'
);
};
}
You can try below for your componentWillMount
componentWillMount() {
firebase
.auth()
.createUserWithEmailAndPassword('loigin', 'pass')
.then(() => {
firebase.database()
.ref('Users')
.child('AhvRcIT2anTaucSDoOgt2MLNxgZ2').on('value', function (snapshot) {
alert(snapshot.val())
})
.catch(e => alert(e));
})
.catch(error => {
alert(error.message)
})
}