如何在按下导航后退按钮时显示警报,但在按下简单按钮时不显示警报?

问题描述 投票:0回答:1

当我按下反应本机导航的后退按钮时,警报会按预期显示,但是当我按下简单按钮时,我想返回而不显示警报

这是我的代码

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-native react-hooks react-navigation
1个回答
0
投票

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>
  );
};
© www.soinside.com 2019 - 2024. All rights reserved.