我正在使用底部标签导航器开发一个本机应用程序。对于某些导航操作,我希望在继续之前获得用户确认(以使用户不会丢失所做的更改)。
如果用户取消导航,我正在使用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()执行异步块并显示确认对话框时,它不等待响应。取而代之的是无论导航如何(并忽略用户的回答)都继续进行导航。
有没有做这项工作的方法,或者是获得导航操作用户确认的更好方法?
答案 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上,然后单击功能,检查条件是否需要渲染屏幕!