Skip to content

Commit fa28817

Browse files
pawicaotomekzaw
andauthored
Rewrite BokehExample into transforms in the example app (#8415)
## Summary This PR optimizes the Bokeh example in the example app, by rewriting: - the animation logic to use `withRepeat` instead of JS intervals - introducing props-based `Circle` component for potential reusability in some other examples - animating the `transform` property instead of `left` and `top` directly ## Test plan --------- Signed-off-by: Oskar Pawica <[email protected]> Co-authored-by: Tomasz Zawadzki <[email protected]>
1 parent a9c36e6 commit fa28817

File tree

1 file changed

+83
-42
lines changed

1 file changed

+83
-42
lines changed

apps/common-app/src/apps/reanimated/examples/BokehExample.tsx

Lines changed: 83 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,84 @@
1-
import React, { useState } from 'react';
1+
import { useEffect, useMemo } from 'react';
22
import { Dimensions, StyleSheet, View } from 'react-native';
33
import Animated, {
44
Easing,
55
useAnimatedStyle,
6-
useReducedMotion,
76
useSharedValue,
7+
withRepeat,
88
withTiming,
99
} from 'react-native-reanimated';
1010

1111
const { width, height } = Dimensions.get('window');
1212

13-
function randBetween(min: number, max: number) {
14-
return min + Math.random() * (max - min);
13+
interface CircleProps {
14+
size: number;
15+
opacity: number;
16+
duration: number;
17+
startX: number;
18+
startY: number;
19+
endX: number;
20+
endY: number;
21+
startHue: number;
22+
endHue: number;
1523
}
1624

17-
function Circle() {
18-
const shouldReduceMotion = useReducedMotion();
25+
function Circle({
26+
size,
27+
opacity,
28+
duration,
29+
startX,
30+
startY,
31+
endX,
32+
endY,
33+
startHue,
34+
endHue,
35+
}: CircleProps) {
36+
const left = useSharedValue(startX);
37+
const top = useSharedValue(startY);
38+
const hue = useSharedValue(startHue);
1939

20-
const [power] = useState(randBetween(0, 1));
21-
const [duration] = useState(randBetween(2000, 3000));
40+
useEffect(() => {
41+
left.value = startX;
42+
top.value = startY;
43+
hue.value = startHue;
2244

23-
const size = 100 + power * 250;
24-
const opacity = 0.1 + (1 - power) * 0.1;
25-
const config = { duration, easing: Easing.linear };
26-
27-
const left = useSharedValue(randBetween(0, width) - size / 2);
28-
const top = useSharedValue(randBetween(0, height) - size / 2);
29-
const hue = useSharedValue(randBetween(100, 200));
30-
31-
const update = () => {
32-
left.value = withTiming(left.value + randBetween(-100, 100), config);
33-
top.value = withTiming(top.value + randBetween(-100, 100), config);
34-
hue.value = withTiming(hue.value + randBetween(0, 100), config);
35-
};
45+
const config = { duration, easing: Easing.linear };
3646

37-
React.useEffect(() => {
38-
update();
39-
if (shouldReduceMotion) {
40-
return;
41-
}
42-
const id = setInterval(update, duration);
43-
return () => clearInterval(id);
44-
});
47+
left.value = withRepeat(withTiming(endX, config), -1, true);
48+
top.value = withRepeat(withTiming(endY, config), -1, true);
49+
hue.value = withRepeat(withTiming(endHue, config), -1, true);
50+
}, [duration, startX, startY, startHue, endX, endY, endHue, hue, left, top]);
4551

4652
const animatedStyle = useAnimatedStyle(
4753
() => ({
4854
backgroundColor: `hsl(${hue.value},100%,50%)`,
49-
width: size,
50-
height: size,
51-
left: left.value,
52-
top: top.value,
55+
transform: [{ translateX: left.value }, { translateY: top.value }],
5356
}),
5457
[]
5558
);
5659

57-
return <Animated.View style={[styles.circle, { opacity }, animatedStyle]} />;
60+
return (
61+
<Animated.View
62+
style={[
63+
styles.circle,
64+
{ opacity, width: size, height: size },
65+
animatedStyle,
66+
]}
67+
/>
68+
);
5869
}
5970

6071
interface BokehProps {
6172
count: number;
6273
}
6374

6475
function Bokeh({ count }: BokehProps) {
65-
return (
66-
<>
67-
{[...Array(count)].map((_, i) => (
68-
<Circle key={i} />
69-
))}
70-
</>
76+
const circles = useMemo(
77+
() => Array.from({ length: count }, makeBokehCircleParams),
78+
[count]
7179
);
80+
81+
return circles.map((circleProps, i) => <Circle {...circleProps} key={i} />);
7282
}
7383

7484
export default function BokehExample() {
@@ -79,11 +89,42 @@ export default function BokehExample() {
7989
);
8090
}
8191

92+
function randBetween(min: number, max: number) {
93+
return min + Math.random() * (max - min);
94+
}
95+
96+
function makeBokehCircleParams(): CircleProps {
97+
const power = randBetween(0, 1);
98+
const size = 100 + power * 250;
99+
const opacity = 0.1 + (1 - power) * 0.1;
100+
101+
const duration = randBetween(2000, 3000);
102+
103+
const startX = randBetween(0, width) - size / 2;
104+
const startY = randBetween(0, height) - size / 2;
105+
106+
const endX = startX + randBetween(-100, 100);
107+
const endY = startY + randBetween(-100, 100);
108+
109+
const startHue = randBetween(0, 360);
110+
const endHue = randBetween(0, 360);
111+
112+
return {
113+
size,
114+
opacity,
115+
duration,
116+
startX,
117+
startY,
118+
endX,
119+
endY,
120+
startHue,
121+
endHue,
122+
};
123+
}
124+
82125
const styles = StyleSheet.create({
83126
container: {
84127
flex: 1,
85-
alignItems: 'center',
86-
justifyContent: 'center',
87128
backgroundColor: 'black',
88129
overflow: 'hidden',
89130
},

0 commit comments

Comments
 (0)