Reputation: 113
I am working on a simple web browser drawing app using React. The app uses images for the buttons to select which color to draw with. Each of these color button images has the same className='color-button'
I followed this article for how to animate the color button images on click using CSS animation: https://dev.to/samwatts98/how-to-easily-animate-your-react-components-on-click-with-css-keyframes-26mg
The problem is that clicking on any one color button image makes them all animate because they all share className='color-button'. I only want to animate the color button image that was clicked on.
The live version of the app in its current state is here: https://master.d3irlm8kk772s.amplifyapp.com/
Below is the code to set the "push" animation state with hooks plus an additional function I tried that didn't work:
const [push, setPush] = useState(0);
//This function was tried but didn't solve the problem:
function changeSetPush(){
setPush(1);
}
Here is the code for the images themselves. The first image tries the changeSetPush function, but achieves the same result as the other images:
{/* Circle Color Buttons */}
<div style={{width: 96}}>
<img src={BlackCircle} alt='black' className='color-button'
onClick={() => {changePenColor('#000000');
changeSetPush()}} onAnimationEnd={() => setPush(0)} push={push}
/>
<img src={WhiteCircle} alt='white' className='color-button'
onClick={() => {changePenColor('#FFFFFF');
setPush(1)}} onAnimationEnd={() => setPush(0)} push={push}
/>
<img src={RedCircle} alt='red' className='color-button'
onClick={() => {changePenColor('#FE2B01');
setPush(1)}} onAnimationEnd={() => setPush(0)} push={push}
/>
<img src={GreenCircle} alt='green' className='color-button'
onClick={() => {changePenColor('#3FF913');
setPush(1)}} onAnimationEnd={() => setPush(0)} push={push}
/>
<img src={YellowCircle} alt='yellow' className='color-button'
onClick={() => {changePenColor('#FCFC0A');
setPush(1)}} onAnimationEnd={() => setPush(0)} push={push}
/>
<img src={BlueCircle} alt='blue' className='color-button'
onClick={() => {changePenColor('#2A2EFE');
setPush(1)}} onAnimationEnd={() => setPush(0)} push={push}
/>
<img src={OrangeCircle} alt='orange' className='color-button'
onClick={() => {changePenColor('#FF8B00');
setPush(1)}} onAnimationEnd={() => setPush(0)} push={push}
/>
<img src={PurpleCircle} alt='purple' className='color-button'
onClick={() => {changePenColor('#F03EFE');
setPush(1)}} onAnimationEnd={() => setPush(0)} push={push}
/>
</div>
And here is the CSS for the animation:
.color-button {
width: 48px;
height: 48px;
vertical-align: bottom;
}
.color-button[push='1'] {
animation: push 200ms 1;
}
@keyframes push {
25% {
transform:scale(0.95);
}
50% {
transform:scale(0.90);
}
75% {
transform:scale(0.85);
}
100% {
transform:scale(0.80);
}
}
The GitHub repo is here: https://github.com/Johnsensei/oekaki
The React component is a functional component, so I'm not able to use this.setState.
What do I change in the code to get the animation only on the color-button that was clicked?
Thanks for your help.
Upvotes: 1
Views: 2923
Reputation: 113
Ok, it got sorted in a very "React" way to approach the problem.
First, we make a new component called ColorButton
import React, { useState } from 'react';
const ColorButton = ({ alt, onClick, src }) => {
const [pushed, setPushed] = useState(false);
return (<img
src={src}
alt={alt}
className={`color-button ${pushed ? "push" : ""}`}
onClick={() => {
onClick();
setPushed(true);
}}
onAnimationEnd={() => setPushed(false)}
/>)
}
export default ColorButton;
Then we import and implement it into the Main component:
import ColorButton from './ColorButton';
...
<div style={{width: 96}}>
<ColorButton
src={BlackCircle}
alt='black'
onClick={() => changePenColor('#000000')}
/>
<ColorButton
src={WhiteCircle}
alt='white'
onClick={() => changePenColor('#FFFFFF')}
/>
<ColorButton
src={RedCircle}
alt='red'
onClick={() => changePenColor('#FE2B01')}
/>
<ColorButton
src={GreenCircle}
alt='green'
onClick={() => changePenColor('#3FF913')}
/>
<ColorButton
src={YellowCircle}
alt='yellow'
onClick={() => changePenColor('#FCFC0A')}
/>
<ColorButton
src={BlueCircle}
alt='blue'
onClick={() => changePenColor('#2A2EFE')}
/>
<ColorButton
src={OrangeCircle}
alt='orange'
onClick={() => changePenColor('#FF8B00')}
/>
<ColorButton
src={PurpleCircle}
alt='purple'
onClick={() => changePenColor('#F03EFE')}
/>
</div>
And finally, update the CSS animation:
.color-button {
width: 48px;
height: 48px;
vertical-align: bottom;
}
.push {
animation: push 200ms 1;
}
@keyframes push {
25% {
transform:scale(0.95);
}
50% {
transform:scale(0.90);
}
75% {
transform:scale(0.85);
}
100% {
transform:scale(0.80);
}
}
The fix is now live: https://master.d3irlm8kk772s.amplifyapp.com/
This was my first time posting a question to Stack Overflow. Everyone was so helpful and supportive here and in the Discord and Slack channels I was asking for help in too. Special shoutout to Tyler from freeCodeCamp Nashville. Thanks!
Upvotes: 2