Skip to content

Commit a5f0774

Browse files
authored
Merge pull request #3237 from nathan-hadley/fix/actionsheet-state-sync
fix: resolve stale state issue when closing Actionsheet via drag gesture
2 parents 59f12d3 + 7ee54a8 commit a5f0774

File tree

4 files changed

+88
-3
lines changed

4 files changed

+88
-3
lines changed

packages/gluestack-core/src/actionsheet/creator/ActionsheetDragIndicatorWrapper.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ export function ActionsheetDragIndicatorWrapper<T>(
1515
contentSheetHeight,
1616
} = useActionsheetContent('ActionsheetContentContext');
1717

18-
const handleCloseRef = React.useRef(null);
18+
// Keep handleClose ref updated to avoid capturing stale state
19+
const handleCloseRef = React.useRef(handleClose);
20+
React.useEffect(() => {
21+
handleCloseRef.current = handleClose;
22+
}, [handleClose]);
23+
1924
const panResponder = React.useRef(
2025
PanResponder.create({
2126
onStartShouldSetPanResponder: () => true,
@@ -37,7 +42,7 @@ export function ActionsheetDragIndicatorWrapper<T>(
3742
toValue: { x: 0, y: contentSheetHeight.current },
3843
duration: 200,
3944
useNativeDriver: true,
40-
}).start(handleClose);
45+
}).start(() => handleCloseRef.current());
4146
} else {
4247
Animated.spring(pan, {
4348
toValue: { x: 0, y: 0 },
@@ -54,7 +59,7 @@ export function ActionsheetDragIndicatorWrapper<T>(
5459
toValue: { x: 0, y: contentSheetHeightWithSnapPoint },
5560
duration: 200,
5661
useNativeDriver: true,
57-
}).start(handleClose);
62+
}).start(() => handleCloseRef.current());
5863
} else {
5964
Animated.spring(pan, {
6065
toValue: { x: 0, y: 0 },

src/components/ui/actionsheet/docs/index.mdx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
title: gluestack-ui ActionSheet | Installation, Usage & API
33
description: Discover gluestack-ui’s ActionSheet for Expo, React & React Native. Create smooth action sheets with ease. Check our docs to learn more
44
---
5+
56
import { Tabs, TabItem } from '@/docs-components/tabs';
67
import ManualInstallationNote from '@/docs-components/manual-installation-note';
78
import {
@@ -234,6 +235,12 @@ Demonstrates a common UI pattern known as keyboard handling or keyboard scrollin
234235

235236
/// {Example:with-snappoints} ///
236237

238+
### Selection with State Persistence
239+
240+
This example demonstrates proper state handling when closing the actionsheet via drag gesture. Users can select a notification preference, and the selection is correctly saved whether they close by dragging or clicking the backdrop.
241+
242+
/// {Example:state} ///
243+
237244
/// {Example:icons} ///
238245

239246
/// {Example:virtualized-list} ///
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"title": "Selection with State Persistence",
3+
"argTypes": {},
4+
"reactLive": {
5+
"Actionsheet": "@/components/ui/actionsheet",
6+
"ActionsheetContent": "@/components/ui/actionsheet",
7+
"ActionsheetDragIndicator": "@/components/ui/actionsheet",
8+
"ActionsheetDragIndicatorWrapper": "@/components/ui/actionsheet",
9+
"ActionsheetBackdrop": "@/components/ui/actionsheet",
10+
"Button": "@/components/ui/button",
11+
"ButtonText": "@/components/ui/button",
12+
"Text": "@/components/ui/text",
13+
"Heading": "@/components/ui/heading",
14+
"VStack": "@/components/ui/vstack",
15+
"Radio": "@/components/ui/radio",
16+
"RadioGroup": "@/components/ui/radio",
17+
"RadioLabel": "@/components/ui/radio",
18+
"RadioIndicator": "@/components/ui/radio",
19+
"RadioIcon": "@/components/ui/radio",
20+
"CircleIcon": "@/components/ui/icon"
21+
}
22+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
function App() {
2+
const [showActionsheet, setShowActionsheet] = React.useState(false);
3+
const [preference, setPreference] = React.useState('all');
4+
const [tempPreference, setTempPreference] = React.useState('all');
5+
6+
const handleClose = () => {
7+
setPreference(tempPreference);
8+
setShowActionsheet(false);
9+
};
10+
11+
const options = [
12+
{ value: 'all', label: 'All Notifications' },
13+
{ value: 'mentions', label: 'Mentions Only' },
14+
{ value: 'off', label: 'Off' },
15+
];
16+
17+
return (
18+
<>
19+
<VStack space="md">
20+
<Text>Current: {options.find(o => o.value === preference)?.label}</Text>
21+
<Button onPress={() => {
22+
setTempPreference(preference);
23+
setShowActionsheet(true);
24+
}}>
25+
<ButtonText>Change Preference</ButtonText>
26+
</Button>
27+
</VStack>
28+
<Actionsheet isOpen={showActionsheet} onClose={handleClose}>
29+
<ActionsheetBackdrop />
30+
<ActionsheetContent>
31+
<ActionsheetDragIndicatorWrapper>
32+
<ActionsheetDragIndicator />
33+
</ActionsheetDragIndicatorWrapper>
34+
<VStack className="w-full p-4" space="xl">
35+
<Heading size="lg">Preferences</Heading>
36+
<RadioGroup value={tempPreference} onChange={setTempPreference} className="gap-4">
37+
{options.map((option) => (
38+
<Radio key={option.value} value={option.value} className="justify-between">
39+
<RadioLabel>{option.label}</RadioLabel>
40+
<RadioIndicator>
41+
<RadioIcon as={CircleIcon} />
42+
</RadioIndicator>
43+
</Radio>
44+
))}
45+
</RadioGroup>
46+
</VStack>
47+
</ActionsheetContent>
48+
</Actionsheet>
49+
</>
50+
);
51+
}

0 commit comments

Comments
 (0)