Skip to content

Commit 3c60866

Browse files
committed
Fix pressed state not clearing on scroll in StoryItem
Replace Pressable inside Link.Trigger (which broke navigation) with original View + onTouchMove handler. onTouchMove fires when the finger moves during scroll, clearing the pressed state even when onTouchCancel doesn't fire reliably.
1 parent e9e2c65 commit 3c60866

1 file changed

Lines changed: 49 additions & 17 deletions

File tree

components/StoryItem.jsx

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useState } from 'react';
1+
import { useCallback, useEffect, useRef, useState } from 'react';
22
import { Pressable, StyleSheet, View } from 'react-native';
33

44
import { Link } from 'expo-router';
@@ -72,6 +72,8 @@ export default function StoryItem({ id, position }) {
7272
const isJob = type === 'job';
7373
const [pressed, setPressed] = useState(false);
7474
const [pressed2, setPressed2] = useState(false);
75+
const pressTimer = useRef(null);
76+
const pressTimer2 = useRef(null);
7577

7678
if (!story) {
7779
console.warn(`Story not found: ${id} (${position})`);
@@ -80,13 +82,40 @@ export default function StoryItem({ id, position }) {
8082

8183
const shortCommentsCount = shortenNumber(comments_count);
8284

85+
const handleTouchStart = () => {
86+
clearTimeout(pressTimer.current);
87+
pressTimer.current = setTimeout(() => setPressed(true), 130);
88+
};
89+
90+
const handleTouchEnd = () => {
91+
clearTimeout(pressTimer.current);
92+
setPressed(false);
93+
};
94+
95+
const handleTouchStart2 = () => {
96+
clearTimeout(pressTimer2.current);
97+
pressTimer2.current = setTimeout(() => setPressed2(true), 130);
98+
};
99+
100+
const handleTouchEnd2 = () => {
101+
clearTimeout(pressTimer2.current);
102+
setPressed2(false);
103+
};
104+
83105
const shareHandler = useCallback(() => {
84106
const shareUrl = httpLink
85107
? url
86108
: `https://news.ycombinator.com/item?id=${id}`;
87109
openShare({ url: shareUrl });
88110
}, [httpLink, url, id]);
89111

112+
useEffect(() => {
113+
return () => {
114+
clearTimeout(pressTimer.current);
115+
clearTimeout(pressTimer2.current);
116+
};
117+
}, []);
118+
90119
const storyInfoContent = (
91120
<>
92121
<Text type={visited && 'insignificant'}>{title}</Text>
@@ -187,14 +216,15 @@ export default function StoryItem({ id, position }) {
187216
<View style={styles.flex}>
188217
<Link href={`/story/${id}?tab=web`} push>
189218
<Link.Trigger>
190-
<Pressable
191-
unstable_pressDelay={130}
192-
onPressIn={() => setPressed(true)}
193-
onPressOut={() => setPressed(false)}
219+
<View
220+
onTouchStart={handleTouchStart}
221+
onTouchEnd={handleTouchEnd}
222+
onTouchMove={handleTouchEnd}
223+
onTouchCancel={handleTouchEnd}
194224
style={styles.storyInfo}
195225
>
196226
{storyInfoContent}
197-
</Pressable>
227+
</View>
198228
</Link.Trigger>
199229
<Link.Preview />
200230
<Link.Menu>
@@ -209,13 +239,14 @@ export default function StoryItem({ id, position }) {
209239
</View>
210240
<Link href={`/story/${id}?tab=comments`} push>
211241
<Link.Trigger>
212-
<Pressable
213-
unstable_pressDelay={130}
214-
onPressIn={() => {
242+
<View
243+
onTouchStart={() => {
215244
fetchStory(id);
216-
setPressed2(true);
245+
handleTouchStart2();
217246
}}
218-
onPressOut={() => setPressed2(false)}
247+
onTouchEnd={handleTouchEnd2}
248+
onTouchMove={handleTouchEnd2}
249+
onTouchCancel={handleTouchEnd2}
219250
style={StyleSheet.flatten([
220251
styles.storyComments,
221252
pressed2 && { opacity: 0.5 },
@@ -236,7 +267,7 @@ export default function StoryItem({ id, position }) {
236267
{shortenNumber(comments_count)}
237268
</Text>
238269
)}
239-
</Pressable>
270+
</View>
240271
</Link.Trigger>
241272
<Link.Preview />
242273
<Link.Menu>
@@ -255,17 +286,18 @@ export default function StoryItem({ id, position }) {
255286
<View style={styles.flex}>
256287
<Link href={`/story/${id}?tab=comments`} push>
257288
<Link.Trigger>
258-
<Pressable
259-
unstable_pressDelay={130}
260-
onPressIn={() => setPressed(true)}
261-
onPressOut={() => setPressed(false)}
289+
<View
290+
onTouchStart={handleTouchStart}
291+
onTouchEnd={handleTouchEnd}
292+
onTouchMove={handleTouchEnd}
293+
onTouchCancel={handleTouchEnd}
262294
style={StyleSheet.flatten([
263295
styles.storyInfo,
264296
pressed && { backgroundColor: colors.secondaryBackground },
265297
])}
266298
>
267299
{storyInfoContent}
268-
</Pressable>
300+
</View>
269301
</Link.Trigger>
270302
<Link.Preview />
271303
<Link.Menu>

0 commit comments

Comments
 (0)