反应导航-如何获得用户确认?

时间:2019-08-06 21:29:45

标签: react-native react-navigation

我正在使用底部标签导航器开发一个本机应用程序。对于某些导航操作,我希望在继续之前获得用户确认(以使用户不会丢失所做的更改)。

如果用户取消导航,我正在使用getStateForAction()来阻止导航(每个https://reactnavigation.org/docs/en/routers.html#blocking-navigation-actions):

const defaultGetStateForAction = AppNavigator.router.getStateForAction;
AppNavigator.router.getStateForAction = (action, state) => {
    if (action.type === NavigationActions.NAVIGATE
    &&  state) {
        let previousScreen = state.routes[state.index].routeName;
        let currentScreen = action.routeName;

        if (previousScreen === 'Screen2') {
            (async () => {
                const confirm = await confirmDialog('Abandon Screen2?');
                if (!confirm) {
                    return null; // block navigation
                }
            })();
        }
    }

    return defaultGetStateForAction(action, state);
}

async function confirmDialog(title) {
    return new Promise((resolve, reject) => {
        Alert.alert(
            title,
            null,
            [
                { text: 'Cancel', onPress: () => { resolve(false) }},
                { text: 'Ok', onPress: () => { resolve(true) }},
            ],
            { cancelable: false });
    })
}

这几乎可以工作...除了当getStateForAction()执行异步块并显示确认对话框时,它不等待响应。取而代之的是无论导航如何(并忽略用户的回答)都继续进行导航。

有没有做这项工作的方法,或者是获得导航操作用户确认的更好方法?

2 个答案:

答案 0 :(得分:0)

我找到了一个解决方案:它需要访问导航器,因此我将其作为导航参数传递到每个屏幕中:

Screen.js

componentDidMount() {
    this.props.navigation.setParams({ screenNav: this.props.navigation });
}

然后我可以默认情况下阻止导航,并且仅当/当用户确认时才通过修改 getStateForAction() 进行导航:

AppNavigator.router.getStateForAction = (action, state) => {
    if (action.type === NavigationActions.NAVIGATE
    &&  state) {
        let screenNav = state.routes[state.index].params.screenNav;
        let previousScreen = state.routes[state.index].routeName;
        let currentScreen = action.routeName;

        if (previousScreen === 'Screen2' && !state.isConfirmed) {
            (async () => {
                const confirm = await confirmDialog('Abandon Screen2?');
                if (confirm) {
                    state.isConfirmed = true;
                    screenNav.navigate(nextScreen); // navigate on confirmation
                }
            })();
            return null; // block navigation by default
        }

        state.isConfirmed = false;
    }

    return defaultGetStateForAction(action, state);
}

注意:标记 state.isConfirmed 是避免无限循环所必需的,因为screenNav.navigate(nextScreen)立即使用相同的参数再次调用 getStateForAction()

答案 1 :(得分:-1)

您可能需要使用redux。将数据保存在redux上,然后单击功能,检查条件是否需要渲染屏幕!