In this tutorial, you will learn, how to do hand clap animation by clicking on a button.
1. How to use a counter in react native
2. Conditional block for showing image using state variables
3. How to use JavaScript splice function to remove an object
4. Use indexOf method to find the index of a given value in the array
5. How to use setTimeOut function to delay rerender of next animation
6. Using useEffect() to run certain logic after every render
See the end result first of Hand Clap
1. How to use a counter in react native
First we want to keep track of the number of claps has done. We save them in a state variable name countClaps.
const [countClaps, setCountClaps]=useState(0);
Each time the onPress handler is invoked, we countClaps is increased and save in an array. The array is also saved in a state variable called claps
const [claps, setClaps]=useState([]);
We initialized it to zero. The below function increases the countClaps and save it to claps array.
const clapHand=()=>{
setCountClaps(
countClaps+1
)
claps.push(countClaps);
}
We used JavaScript push to save them for future usage.
2. Conditional block for showing using image state variables
Once our app is launched the clap button should be different once it's clapped. So the images should be different before and after the clap happens. We change images once the countClaps becomes 1. The initial value is 0. Once the onPress function is triggered countClaps become 1 and then we can change image.
const clapIcon = countClaps > 0 ? <Image source={require("../assets/clapped.png")} style={styles.img} />
: <Image source={require("../assets/clap.png")} style={styles.img} />
So here we check countClap is 0 or more than 1. This is how we change image from clap.png to clapped.png
3. How to use JavaScript splice function to remove an object
We use the JavaScript splice() method remove objects from our claps array. We provided the second parameter a non-zero value to remove a clap object from the array. First we find the index for a given object using JavaScript indexOf method and then we use the index to remove the object using splice function. All you need to remember is that, splice() method helps you remove a node or object from array. In our application, we don't to keep all the objects. We can set them to null once the animation is done. So we use splice() function to do it. This function is get called once the animation is completed.
const animationCompleted=(newCount)=>{
claps.splice(claps.indexOf(newCount), 1)
setClaps([])
}
4. Use indexOf method to find the index of a given value in the array
This method is another big rescuer when you don't which object to remove. IndexOf() method let's us the index of object.
5. How to use setTimeOut function to delay rerender of next animation
We used setTimeOut function to reset the animation 500 milliseconds. Each time the animation is done through Animated.parallel function, we use the start() callback to reset the animation. We call animaitonCompleted() method in the start callback. But we don't want to call this completion method immediately. We want to call it 0.5 seconds. Hence setTimeout method comes to help us.
6. Using useEffect() to run certain logic after every render
We have side-effects in our code. Side effects are network request, DOM manipulating, timer function like setTimeOut. We have used setTimeOut method, so putting this method inside useEffect() will cause it run independently after every render. The hook useEffect() takes two parameters. First one is the callback for running logic, second one is the dependencies.
We did not provide any dependency, which makes sure, that the hook useEffect() gets called after every render. If you provide an empty array as the dependency parameter, it will get called only once after initial rendering. Learn more about useEffect() hook.
The complete code is given below
import React, { useEffect, useState } from 'react';
import {View, StyleSheet, TouchableOpacity, Image, Animated, Text} from 'react-native';
function ButtonClaps(props) {
const [countClaps, setCountClaps]=useState(0);
const [claps, setClaps]=useState([]);
const clapHand=()=>{
setCountClaps(
countClaps+1
)
claps.push(countClaps);
}
const clapIcon = countClaps > 0 ? <Image source={require("../assets/clapped.png")} style={styles.img} />
: <Image source={require("../assets/clap.png")} style={styles.img} />
const RenderBubble=()=>{
return(
claps.map(newCount=><BubbleHand animationCompleted={animationCompleted} newCount={newCount} key={newCount}/>)
)
}
const animationCompleted=(newCount)=>{
claps.splice(claps.indexOf(newCount), 1)
setClaps([])
}
return (
<View style={styles.container}>
{RenderBubble()}
<TouchableOpacity
style={styles.clapButton}
activeOpacity={0.8}
onPress={clapHand}
>
{clapIcon}
</TouchableOpacity>
</View>
);
}
const BubbleHand=(props)=>{
const [bubbleAnimaiton, setBubbAnimation] = useState(new Animated.Value(0));
const [bubbleAnimaitonOpacity, setBubbleAnimationOpacity] = useState(new Animated.Value(0));
useEffect(()=>{
Animated.parallel([
Animated.timing(bubbleAnimaiton,{
toValue:-550,
duration:2000,
useNativeDriver:true,
}),
Animated.timing(bubbleAnimaitonOpacity, {
toValue:1,
duration:2000,
useNativeDriver:true,
})
]).start(()=>{
setTimeout(()=>{
props.animationCompleted(props.newCount)
}, 500)
});
})
const bubble ={
transform:[
{translateY:bubbleAnimaiton}
],
opacity:bubbleAnimaitonOpacity,
}
return(
<Animated.View style={[styles.bubble, bubble]}>
<Text style={styles.text}>
+{props.newCount}
</Text>
</Animated.View>
)
}
const styles=StyleSheet.create({
bubble:{
width:100,
height:100,
borderRadius:50,
backgroundColor:"#fc5c64",
position:"absolute",
left:150,
bottom:200,
justifyContent:"center",
alignItems:"center",
},
container:{
flex:1,
backgroundColor:"orange"
},
clapButton:{
width:100,
height:100,
borderRadius:50,
backgroundColor:"white",
position:"absolute",
left:150,
bottom:200,
justifyContent:"center",
alignItems:"center",
shadowColor:"black",
shadowOffset:{
width:5,
height:5
},
shadowOpacity:0.7
},
img:{
width:60,
height:60,
},
text:{
color:"white",
fontSize:22
}
});
export default ButtonClaps;