我需要阻止StackNavigator的默认行为,它创建多个屏幕副本并将它们保存在内存中(并具有随机卸载行为)。我只想要每个屏幕的一个实例。
我按照下面的代码覆盖了路由器。它的作用是在导航时查找堆栈中的现有屏幕,如果存在,则将其移动到当前索引,将其他所有内容混洗。它可能比需要的更复杂,但在我看来,你不应该乱用当前的索引。
const AppNavigator = StackNavigator(Routes, {});
//move this into routes.js if it works
const prevGetStateForAction = AppNavigator.router.getStateForAction;
AppNavigator.router = {
...AppNavigator.router,
getStateForAction(action, state) {
//check if route is already on stack and go to it instead of adding a new item on stack
//NOTE: This will break things like being able to have push notification messages on the same route but different messages and being able to go back through them
//if that becomes a problem just opt out for certain route names eg if(action.routeName == "Messages") return prevGetStateForAction(aciton,state)
if(state && action.type == 'Navigation/NAVIGATE' && state.routes !== undefined ) {
//console.log("getStateForAction state",state,"action,",action);
var i = -1;
//try find the route in the stack
for(var c =0; c < state.routes.length; c++) {
if(state.routes[c].routeName == action.routeName) {
i = c;
break;
}
}
//found it but we're already there so do nothing as we're trying to navigate to ourselves
if(i == state.index)
return null;
//didn't find it - add screen to stack - ie call default action
if(i == -1)
return prevGetStateForAction(action,state);
//found it - move it to just after index and increment index - i think
console.log("stacknavigator is trying to duplicate route - moving back to previous route");
var route = state.routes[i];
var routes = state.routes.splice(i,1);
//you've just moved the item that index was pointing at if it was greater than where our item was
var newIndex = 0;
if(state.index > i)
newIndex = state.index -1;
else
newIndex = state.index;
//index was at the end so we just take the array and add our item at the end - no slices needed
if(state.index == state.routes.length -1)
var routes = [ ...routes, route];
else
var routes = [
...state.routes.slice(0,newIndex+1),
route,
...state.routes.slice(state.index+1)
];
return {
...state,
routes: routes,
index: newIndex
}
}
return prevGetStateForAction(action,state);
}
它可以工作很长一段时间(因为你可以愉快地导航而不会创建重复项)但最终会失败,我无法解决原因 - 你可以看到我的console.log调用,当一个骗局被击中但是从来没有命中 - 代码正在运行但是。这可能是代码中的一个错误,但我觉得它更可能是我错过的React Navigation行为。可能是我没有考虑的导航/后退和后退按钮行为。
有人可以更正我的代码或提供防止堆叠中重复屏幕的替代方法吗?
编辑 - 因为我无法在评论中填写代码
我有另一个想法,在我看来,我可能不应该试图保持索引相同,因为我的屏幕现在将在堆栈的末尾。
无论如何,它似乎已经解决了问题,因为我无法重现重复的屏幕。
const AppNavigator = StackNavigator(Routes, {});
//move this into routes.js if it works
const prevGetStateForAction = AppNavigator.router.getStateForAction;
AppNavigator.router = {
...AppNavigator.router,
getStateForAction(action, state) {
//check if route is already on stack and go to it instead of adding a new item on stack
//NOTE: This will break things like being able to have push notification messages on the same route but different messages and being able to go back through them
//if that becomes a problem just opt out for certain route names eg if(action.routeName == "Messages") return prevGetStateForAction(aciton,state)
if(state && action.type == 'Navigation/NAVIGATE' && state.routes !== undefined ) {
//console.log("getStateForAction state",state,"action,",action);
var i = -1;
//try find the route in the stack
for(var c =0; c < state.routes.length; c++) {
if(state.routes[c].routeName == action.routeName) {
i = c;
break;
}
}
//found it but we're already there so do nothing as we're trying to navigate to ourselves
if(i == state.index) {
console.log("getstateforaction() - you're trying to navigate to yourself!");
return null;
}
//didn't find it - add screen to stack - ie call default action
if(i == -1) {
console.log("getstateforaction() - no duplicate screen found");
return prevGetStateForAction(action,state);
}
//found it - move it to just after index and increment index - i think
console.log("stacknavigator is trying to duplicate route - moving back to previous route");
var route = state.routes[i];
var routes = state.routes;
routes.splice(i,1);
routes = [
...routes,
route
];
newIndex = routes.length-1;
return {
...state,
routes: routes,
index: newIndex
}
}
return prevGetStateForAction(action,state);
}
答案 0 :(得分:0)
编辑后的回复中提供的代码解决了这个问题,并且已经工作了一个星期而没有任何问题。
我希望它可以帮助其他人面对同样的问题。