当我按下反应本机导航的后退按钮时,警报会按预期显示,但是当我按下简单按钮时,我想返回而不显示警报
这是我的代码
const EditTextScreen = ({ navigation }) => {
const [text, setText] = React.useState('');
const [buttonClicked,setButtonClicked] = React.useState(false)
const hasUnsavedChanges = Boolean(text);
React.useEffect(
() =>
navigation.addListener('beforeRemove', (e) => {
const action = e.data.action;
if (!hasUnsavedChanges && buttonClicked) {
return;
}
e.preventDefault();
Alert.alert(
'Discard changes?',
'You have unsaved changes. Are you sure to discard them and leave the screen?',
[
{ text: "Don't leave", style: 'cancel', onPress: () => {} },
{
text: 'Discard',
style: 'destructive',
onPress: () => navigation.dispatch(action),
},
]
);
}),
[hasUnsavedChanges,buttonClicked, navigation]
);
return (
<View style={styles.content}>
<TextInput
autoFocus
style={styles.input}
value={text}
placeholder="Type something…"
onChangeText={setText}
/>
<Button onPress={()=>{
setButtonClicked(true)
navigation.goBack()
}}>confirm</Button>
</View>
);
};
当按下确认按钮时,状态更改为 true,因此用户应该能够返回而不会收到警报,但我仍然收到警报。
React 状态更新是异步处理的,因此当单击简单按钮时 两个
setButtonClicked(true)
将状态更新排入队列 和 navigation.goBack()
基本上同时调用,beforeRemove
处理程序不会知道或等待处理 React 状态更新。
您可以在此处使用 React ref,因为它们可以在 React 组件渲染周期中随时发生变化。
实现示例:
const EditTextScreen = ({ navigation }) => {
const [text, setText] = React.useState('');
const buttonClickedRef = React.useref(false);
const hasUnsavedChanges = Boolean(text);
React.useEffect(() => {
const beforeRemoveHandler = (e) => {
const action = e.data.action;
// Include check that simple button was clicked
if (!hasUnsavedChanges && buttonClickedRef.current) {
// Reset that simple button was clicked
buttonClickedRef.current = false;
return;
}
e.preventDefault();
Alert.alert(
'Discard changes?',
'You have unsaved changes. Are you sure to discard them and leave the screen?',
[
{ text: "Don't leave", style: 'cancel', onPress: () => {} },
{
text: 'Discard',
style: 'destructive',
onPress: () => navigation.dispatch(action),
},
]
);
}
const unsubscribe = navigation.addListener('beforeRemove', beforeRemoveHandler);
// Return useEffect cleanup function to unsubscribe event listeners
return unsubscribe;
}, [hasUnsavedChanges, buttonClicked, navigation]);
return (
<View style={styles.content}>
<TextInput
autoFocus
style={styles.input}
value={text}
placeholder="Type something…"
onChangeText={setText}
/>
<Button
onPress={() => {
// Set true that simple button was clicked
buttonClickedRef.current = true;
navigation.goBack();
}}
>
confirm
</Button>
</View>
);
};