Utility library for React Native Reanimated and Gesture Handler providing mathematical functions, animations, transformations, and helper utilities for building complex gesture-driven animations.
—
React hooks for creating smooth transitions with spring and timing animations, providing convenient wrappers around React Native Reanimated's animation functions.
import type { WithSpringConfig, WithTimingConfig } from "react-native-reanimated";Create spring-based transitions that respond to state changes with natural, physics-based motion.
/**
* Create spring transition based on state
* @param state - Boolean or numeric state to animate
* @param config - Optional spring configuration
* @returns Animated value that springs to target
*/
function useSpring(
state: boolean | number,
config?: WithSpringConfig
): Animated.DerivedValue<number>;Usage Example:
import { useSpring } from "react-native-redash";
import { useAnimatedStyle } from "react-native-reanimated";
import { useState } from "react";
export const SpringButton = () => {
const [isPressed, setIsPressed] = useState(false);
// Spring animation for scale
const scale = useSpring(isPressed, {
damping: 15,
stiffness: 200,
mass: 1
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }]
}));
return (
<Animated.View
style={[{ width: 100, height: 100, backgroundColor: 'blue' }, animatedStyle]}
onTouchStart={() => setIsPressed(true)}
onTouchEnd={() => setIsPressed(false)}
/>
);
};Create timing-based transitions with customizable duration and easing curves.
/**
* Create timing transition based on state
* @param state - Boolean or numeric state to animate
* @param config - Optional timing configuration
* @returns Animated value that times to target
*/
function useTiming(
state: boolean | number,
config?: WithTimingConfig
): Animated.DerivedValue<number>;Usage Example:
import { useTiming } from "react-native-redash";
import { useAnimatedStyle } from "react-native-reanimated";
import { Easing } from "react-native-reanimated";
import { useState } from "react";
export const TimingTransition = () => {
const [isVisible, setIsVisible] = useState(false);
// Timing animation for opacity
const opacity = useTiming(isVisible, {
duration: 300,
easing: Easing.inOut(Easing.ease)
});
// Timing animation for position
const translateY = useTiming(isVisible ? 0 : 100, {
duration: 500,
easing: Easing.out(Easing.cubic)
});
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [{ translateY: translateY.value }]
}));
return (
<>
<TouchableOpacity onPress={() => setIsVisible(!isVisible)}>
<Text>Toggle</Text>
</TouchableOpacity>
<Animated.View
style={[
{ width: 100, height: 100, backgroundColor: 'red' },
animatedStyle
]}
/>
</>
);
};Both hooks work with numeric values, not just booleans.
import { useSpring, useTiming } from "react-native-redash";
import { useState } from "react";
export const NumericTransitions = () => {
const [value, setValue] = useState(0);
// Spring to numeric value
const springValue = useSpring(value * 100, {
damping: 20,
stiffness: 100
});
// Timing to numeric value
const timingValue = useTiming(value * 200, {
duration: 1000
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: springValue.value },
{ translateY: timingValue.value }
]
}));
return (
<View>
<Slider
value={value}
onValueChange={setValue}
minimumValue={0}
maximumValue={1}
/>
<Animated.View style={[styles.box, animatedStyle]} />
</View>
);
};Combine multiple transition hooks for complex animations.
import { useSpring, useTiming } from "react-native-redash";
import { useState, useEffect } from "react";
export const ComplexTransition = () => {
const [currentTab, setCurrentTab] = useState(0);
const [isLoading, setIsLoading] = useState(false);
// Spring animation for tab indicator
const tabPosition = useSpring(currentTab * 100, {
damping: 25,
stiffness: 300
});
// Timing animation for loading state
const loadingOpacity = useTiming(isLoading, {
duration: 200
});
// Spring animation for content scale
const contentScale = useSpring(isLoading ? 0.95 : 1, {
damping: 20,
stiffness: 200
});
const tabIndicatorStyle = useAnimatedStyle(() => ({
transform: [{ translateX: tabPosition.value }]
}));
const contentStyle = useAnimatedStyle(() => ({
opacity: 1 - loadingOpacity.value * 0.5,
transform: [{ scale: contentScale.value }]
}));
const loadingStyle = useAnimatedStyle(() => ({
opacity: loadingOpacity.value
}));
return (
<View>
{/* Tab Indicator */}
<Animated.View style={[styles.tabIndicator, tabIndicatorStyle]} />
{/* Content */}
<Animated.View style={[styles.content, contentStyle]}>
{/* Content here */}
</Animated.View>
{/* Loading Overlay */}
<Animated.View style={[styles.loadingOverlay, loadingStyle]}>
<ActivityIndicator />
</Animated.View>
</View>
);
};Both hooks automatically handle state changes and create smooth transitions:
import { useSpring } from "react-native-redash";
import { useState, useCallback } from "react";
export const PerformantComponent = () => {
const [count, setCount] = useState(0);
// Automatically animates when count changes
const animatedCount = useSpring(count, {
damping: 15,
stiffness: 100
});
// Memoize handlers to prevent unnecessary re-renders
const increment = useCallback(() => {
setCount(prev => prev + 1);
}, []);
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ scale: 1 + animatedCount.value * 0.1 },
{ rotate: `${animatedCount.value * 10}deg` }
]
}));
return (
<TouchableOpacity onPress={increment}>
<Animated.View style={[styles.counter, animatedStyle]}>
<Text>{count}</Text>
</Animated.View>
</TouchableOpacity>
);
};Configuration Options:
The hooks accept the same configuration options as React Native Reanimated's withSpring and withTiming. These types are imported from react-native-reanimated:
WithSpringConfig:
damping?: number - Damping coefficient (default: 10)mass?: number - Mass of the object (default: 1)stiffness?: number - Spring stiffness (default: 100)overshootClamping?: boolean - Prevent overshooting (default: false)restDisplacementThreshold?: number - Threshold for rest detection (default: 0.01)restSpeedThreshold?: number - Speed threshold for rest detection (default: 2)WithTimingConfig:
duration?: number - Animation duration in milliseconds (default: 300)easing?: EasingFunction - Easing function from react-native-reanimated (default: Easing.inOut(Easing.quad))Best Practices:
useSpring for interactive elements (buttons, toggles, gestures)useTiming for sequential animations or precise timing controlInstall with Tessl CLI
npx tessl i tessl/npm-react-native-redash