Efficient Animation Handling in React
Animations in React require special consideration to ensure smooth performance while maintaining the declarative nature of React components. Here are the best practices for implementing efficient animations.
Common Animation Mistakes
// ❌ Inefficient - Direct DOM manipulation and frequent re-renders
function FadeInElement() {
const [opacity, setOpacity] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setOpacity(prev => Math.min(prev + 0.1, 1));
}, 16);
return () => clearInterval(interval);
}, []);
return <div style={{ opacity }}>Fading In</div>;
}
Recommended Animation Approaches
1. CSS Transitions (Simplest Approach)
// ✅ Efficient - CSS handles the animation
const FadeInDiv = styled.div`
opacity: 0;
transition: opacity 0.5s ease-in-out;
&.visible {
opacity: 1;
}
`;
function FadeInComponent() {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
setIsVisible(true);
}, []);
return <FadeInDiv className={isVisible ? 'visible' : ''}>Content</FadeInDiv>;
}
2. CSS Animations with Keyframes
// ✅ Performant - GPU accelerated
const Bounce = styled.div`
animation: bounce 1s infinite;
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
`;
function BouncingElement() {
return <Bounce>Bouncing!</Bounce>;
}
3. React Spring (Physics-based Animations)
// ✅ Smooth - uses spring physics
import { useSpring, animated } from 'react-spring';
function FadeIn() {
const props = useSpring({
opacity: 1,
from: { opacity: 0 },
config: { duration: 1000 }
});
return <animated.div style={props}>I will fade in</animated.div>;
}
4. Framer Motion (Production-ready Animations)
// ✅ Declarative and powerful
import { motion } from 'framer-motion';
function AnimatedBox() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
Animated Content
</motion.div>
);
}
Performance Optimization Techniques
1. Using will-change Property
// Hint browser about upcoming animations
const AnimBox = styled.div`
will-change: transform, opacity;
transition: transform 0.3s ease;
`;
2. Hardware Acceleration
// Leverage GPU for smoother animations
const HardwareAccelerated = styled.div`
transform: translateZ(0);
backface-visibility: hidden;
perspective: 1000px;
`;
3. Animation Batching with useReducer
// ✅ Better for complex animation states
function AnimatedComponent() {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
const frame = requestAnimationFrame(() => {
dispatch({ type: 'UPDATE_POSITION' });
});
return () => cancelAnimationFrame(frame);
}, [state]);
return <div style={{ transform: `translateX(${state.x}px)` }} />;
}
When to Use Different Animation Approaches
Technique | Best For | Performance | Complexity |
---|---|---|---|
CSS Transitions | Simple state changes | Excellent | Low |
CSS Animations | Complex keyframe animations | Excellent | Medium |
React Spring | Physics-based motion | Very Good | Medium |
Framer Motion | Production-ready complex animations | Good | High |
requestAnimationFrame | Game-like animations | Good | High |
Common Pitfalls to Avoid
- Using setTimeout/setInterval for animations (use requestAnimationFrame instead)
- Triggering layout thrashing by reading/writing DOM properties repeatedly
- Animating expensive CSS properties like margin or top (use transform instead)
- Over-animating – not all UI elements need motion
- Forgetting to clean up animation frames or timeouts
Best Practices
- Prefer CSS animations for simple effects
- Use transform and opacity – they’re cheapest to animate
- Avoid animating layout properties (width, height, margin, padding)
- Debounce rapid state changes that trigger animations
- Use the will-change property judiciously
- Test animations on low-power devices
- Provide reduced motion alternatives for accessibility
// Reduced motion example
const MotionBox = styled.div`
@media (prefers-reduced-motion: reduce) {
animation: none;
transition: none;
}
`;
Remember that smooth animations should enhance user experience, not hinder performance. Always profile your animations using Chrome DevTools’ Performance tab to ensure they run at 60fps.