0
# Transition Hooks
1
2
React hooks for creating smooth transitions with spring and timing animations, providing convenient wrappers around React Native Reanimated's animation functions.
3
4
```typescript
5
import type { WithSpringConfig, WithTimingConfig } from "react-native-reanimated";
6
```
7
8
## Capabilities
9
10
### Spring Transitions
11
12
Create spring-based transitions that respond to state changes with natural, physics-based motion.
13
14
```typescript { .api }
15
/**
16
* Create spring transition based on state
17
* @param state - Boolean or numeric state to animate
18
* @param config - Optional spring configuration
19
* @returns Animated value that springs to target
20
*/
21
function useSpring(
22
state: boolean | number,
23
config?: WithSpringConfig
24
): Animated.DerivedValue<number>;
25
```
26
27
**Usage Example:**
28
29
```typescript
30
import { useSpring } from "react-native-redash";
31
import { useAnimatedStyle } from "react-native-reanimated";
32
import { useState } from "react";
33
34
export const SpringButton = () => {
35
const [isPressed, setIsPressed] = useState(false);
36
37
// Spring animation for scale
38
const scale = useSpring(isPressed, {
39
damping: 15,
40
stiffness: 200,
41
mass: 1
42
});
43
44
const animatedStyle = useAnimatedStyle(() => ({
45
transform: [{ scale: scale.value }]
46
}));
47
48
return (
49
<Animated.View
50
style={[{ width: 100, height: 100, backgroundColor: 'blue' }, animatedStyle]}
51
onTouchStart={() => setIsPressed(true)}
52
onTouchEnd={() => setIsPressed(false)}
53
/>
54
);
55
};
56
```
57
58
### Timing Transitions
59
60
Create timing-based transitions with customizable duration and easing curves.
61
62
```typescript { .api }
63
/**
64
* Create timing transition based on state
65
* @param state - Boolean or numeric state to animate
66
* @param config - Optional timing configuration
67
* @returns Animated value that times to target
68
*/
69
function useTiming(
70
state: boolean | number,
71
config?: WithTimingConfig
72
): Animated.DerivedValue<number>;
73
```
74
75
**Usage Example:**
76
77
```typescript
78
import { useTiming } from "react-native-redash";
79
import { useAnimatedStyle } from "react-native-reanimated";
80
import { Easing } from "react-native-reanimated";
81
import { useState } from "react";
82
83
export const TimingTransition = () => {
84
const [isVisible, setIsVisible] = useState(false);
85
86
// Timing animation for opacity
87
const opacity = useTiming(isVisible, {
88
duration: 300,
89
easing: Easing.inOut(Easing.ease)
90
});
91
92
// Timing animation for position
93
const translateY = useTiming(isVisible ? 0 : 100, {
94
duration: 500,
95
easing: Easing.out(Easing.cubic)
96
});
97
98
const animatedStyle = useAnimatedStyle(() => ({
99
opacity: opacity.value,
100
transform: [{ translateY: translateY.value }]
101
}));
102
103
return (
104
<>
105
<TouchableOpacity onPress={() => setIsVisible(!isVisible)}>
106
<Text>Toggle</Text>
107
</TouchableOpacity>
108
109
<Animated.View
110
style={[
111
{ width: 100, height: 100, backgroundColor: 'red' },
112
animatedStyle
113
]}
114
/>
115
</>
116
);
117
};
118
```
119
120
### Numeric State Transitions
121
122
Both hooks work with numeric values, not just booleans.
123
124
```typescript
125
import { useSpring, useTiming } from "react-native-redash";
126
import { useState } from "react";
127
128
export const NumericTransitions = () => {
129
const [value, setValue] = useState(0);
130
131
// Spring to numeric value
132
const springValue = useSpring(value * 100, {
133
damping: 20,
134
stiffness: 100
135
});
136
137
// Timing to numeric value
138
const timingValue = useTiming(value * 200, {
139
duration: 1000
140
});
141
142
const animatedStyle = useAnimatedStyle(() => ({
143
transform: [
144
{ translateX: springValue.value },
145
{ translateY: timingValue.value }
146
]
147
}));
148
149
return (
150
<View>
151
<Slider
152
value={value}
153
onValueChange={setValue}
154
minimumValue={0}
155
maximumValue={1}
156
/>
157
<Animated.View style={[styles.box, animatedStyle]} />
158
</View>
159
);
160
};
161
```
162
163
### Complex State-Based Animations
164
165
Combine multiple transition hooks for complex animations.
166
167
```typescript
168
import { useSpring, useTiming } from "react-native-redash";
169
import { useState, useEffect } from "react";
170
171
export const ComplexTransition = () => {
172
const [currentTab, setCurrentTab] = useState(0);
173
const [isLoading, setIsLoading] = useState(false);
174
175
// Spring animation for tab indicator
176
const tabPosition = useSpring(currentTab * 100, {
177
damping: 25,
178
stiffness: 300
179
});
180
181
// Timing animation for loading state
182
const loadingOpacity = useTiming(isLoading, {
183
duration: 200
184
});
185
186
// Spring animation for content scale
187
const contentScale = useSpring(isLoading ? 0.95 : 1, {
188
damping: 20,
189
stiffness: 200
190
});
191
192
const tabIndicatorStyle = useAnimatedStyle(() => ({
193
transform: [{ translateX: tabPosition.value }]
194
}));
195
196
const contentStyle = useAnimatedStyle(() => ({
197
opacity: 1 - loadingOpacity.value * 0.5,
198
transform: [{ scale: contentScale.value }]
199
}));
200
201
const loadingStyle = useAnimatedStyle(() => ({
202
opacity: loadingOpacity.value
203
}));
204
205
return (
206
<View>
207
{/* Tab Indicator */}
208
<Animated.View style={[styles.tabIndicator, tabIndicatorStyle]} />
209
210
{/* Content */}
211
<Animated.View style={[styles.content, contentStyle]}>
212
{/* Content here */}
213
</Animated.View>
214
215
{/* Loading Overlay */}
216
<Animated.View style={[styles.loadingOverlay, loadingStyle]}>
217
<ActivityIndicator />
218
</Animated.View>
219
</View>
220
);
221
};
222
```
223
224
### Performance Considerations
225
226
Both hooks automatically handle state changes and create smooth transitions:
227
228
```typescript
229
import { useSpring } from "react-native-redash";
230
import { useState, useCallback } from "react";
231
232
export const PerformantComponent = () => {
233
const [count, setCount] = useState(0);
234
235
// Automatically animates when count changes
236
const animatedCount = useSpring(count, {
237
damping: 15,
238
stiffness: 100
239
});
240
241
// Memoize handlers to prevent unnecessary re-renders
242
const increment = useCallback(() => {
243
setCount(prev => prev + 1);
244
}, []);
245
246
const animatedStyle = useAnimatedStyle(() => ({
247
transform: [
248
{ scale: 1 + animatedCount.value * 0.1 },
249
{ rotate: `${animatedCount.value * 10}deg` }
250
]
251
}));
252
253
return (
254
<TouchableOpacity onPress={increment}>
255
<Animated.View style={[styles.counter, animatedStyle]}>
256
<Text>{count}</Text>
257
</Animated.View>
258
</TouchableOpacity>
259
);
260
};
261
```
262
263
**Configuration Options:**
264
265
The hooks accept the same configuration options as React Native Reanimated's `withSpring` and `withTiming`. These types are imported from `react-native-reanimated`:
266
267
**WithSpringConfig:**
268
- `damping?: number` - Damping coefficient (default: 10)
269
- `mass?: number` - Mass of the object (default: 1)
270
- `stiffness?: number` - Spring stiffness (default: 100)
271
- `overshootClamping?: boolean` - Prevent overshooting (default: false)
272
- `restDisplacementThreshold?: number` - Threshold for rest detection (default: 0.01)
273
- `restSpeedThreshold?: number` - Speed threshold for rest detection (default: 2)
274
275
**WithTimingConfig:**
276
- `duration?: number` - Animation duration in milliseconds (default: 300)
277
- `easing?: EasingFunction` - Easing function from react-native-reanimated (default: Easing.inOut(Easing.quad))
278
279
**Best Practices:**
280
281
1. Use `useSpring` for interactive elements (buttons, toggles, gestures)
282
2. Use `useTiming` for sequential animations or precise timing control
283
3. Combine both for rich, layered animations
284
4. Keep configuration objects stable to avoid unnecessary re-animations
285
5. Use numeric states for smooth value transitions
286
6. Boolean states automatically convert to 0/1 for animations