跳到主要内容
版本:7.x

自定义路由

路由器对象提供了各种辅助方法来处理状态和动作,一个用于更新状态的 reducer 以及一些动作创建器。

路由器负责处理通过调用导航对象上的方法分发的动作。如果路由器无法处理动作,它可以返回 null,这将把动作传播到其他路由器,直到它被处理。

你可以通过构建具有以下函数的对象来创建自己的路由器

  • type - 字符串,表示路由器的类型,例如 'stack''tab''drawer' 等。
  • getInitialState - 返回导航器的初始状态的函数。接收一个带有 routeNamesrouteParamList 属性的 options 对象。
  • getRehydratedState - 从给定的部分状态重新水合完整的 导航状态 的函数。接收一个部分状态对象和一个带有 routeNamesrouteParamList 属性的 options 对象。
  • getStateForRouteNamesChange - 接收当前状态和更新的路由名称列表,并返回新状态的函数。接收状态对象和一个带有 routeNamesrouteParamList 属性的 options 对象。
  • getStateForAction - reducer 函数,接收当前状态和动作,以及一个带有 routeNamesrouteParamList 属性的 options 对象,并返回新状态。如果动作无法处理,则应返回 null
  • getStateForRouteFocus - 接收当前状态和路由键,并返回一个焦点在该路由上的新状态的函数。
  • shouldActionChangeFocus - 确定动作是否也应更改父导航器中的焦点的函数。某些动作(例如 NAVIGATE)可能会更改父级中的焦点。
  • actionCreators - 可选对象,包含动作创建器的列表,例如 pushpop 等。这些将用于向 navigation 对象添加辅助方法以分发这些动作。
信息

路由器对象中的函数应该是纯函数,即它们不应有任何副作用,不应改变参数或外部变量,并且对于相同的输入应返回相同的输出。

示例

const router = {
type: 'tab',

getInitialState({ routeNames, routeParamList }) {
const index =
options.initialRouteName === undefined
? 0
: routeNames.indexOf(options.initialRouteName);

return {
stale: false,
type: 'tab',
key: shortid(),
index,
routeNames,
routes: routeNames.map(name => ({
name,
key: name,
params: routeParamList[name],
})),
};
},

getRehydratedState(partialState, { routeNames, routeParamList }) {
const state = partialState;

if (state.stale === false) {
return state as NavigationState;
}

const routes = state.routes
.filter(route => routeNames.includes(route.name))
.map(
route =>
({
...route,
key: route.key || `${route.name}-${shortid()}`,
params:
routeParamList[route.name] !== undefined
? {
...routeParamList[route.name],
...route.params,
}
: route.params,
} as Route<string>)
);

return {
stale: false,
type: 'tab',
key: shortid(),
index:
typeof state.index === 'number' && state.index < routes.length
? state.index
: 0,
routeNames,
routes,
};
},

getStateForRouteNamesChange(state, { routeNames }) {
const routes = state.routes.filter(route =>
routeNames.includes(route.name)
);

return {
...state,
routeNames,
routes,
index: Math.min(state.index, routes.length - 1),
};
},

getStateForRouteFocus(state, key) {
const index = state.routes.findIndex(r => r.key === key);

if (index === -1 || index === state.index) {
return state;
}

return { ...state, index };
},

getStateForAction(state, action) {
switch (action.type) {
case 'NAVIGATE': {
const index = state.routes.findIndex(
route => route.name === action.payload.name
);

if (index === -1) {
return null;
}

return { ...state, index };
}

default:
return BaseRouter.getStateForAction(state, action);
}
},

shouldActionChangeFocus() {
return false;
},
};

const SimpleRouter = () => router;

export default SimpleRouter;

内置路由器

该库附带了一些标准路由器

  • StackRouter
  • TabRouter
  • DrawerRouter

自定义路由器

你可以重用路由器并根据你的需要覆盖路由器函数,例如自定义现有动作的处理方式、添加其他动作等。

有关如何在现有导航器中使用自定义路由器覆盖路由器的详细信息,请参阅自定义导航器

自定义导航动作

假设你想添加一个自定义动作来清除历史记录

import { TabRouter } from '@react-navigation/native';

const MyTabRouter = (options) => {
const router = TabRouter(options);

return {
...router,
getStateForAction(state, action, options) {
switch (action.type) {
case 'CLEAR_HISTORY':
return {
...state,
routeKeyHistory: [],
};
default:
return router.getStateForAction(state, action, options);
}
},

actionCreators: {
...router.actionCreators,
clearHistory() {
return { type: 'CLEAR_HISTORY' };
},
},
};
};

与其编写自定义路由器来处理自定义动作,不如将函数传递给 dispatch。它更简洁,并且建议这样做,而不是覆盖路由器。

阻止导航动作

有时你可能想要阻止某些导航活动,具体取决于你的路由。假设,如果 isEditingtrue,你想阻止推送新屏幕

import { StackRouter } from '@react-navigation/native';

const MyStackRouter = (options) => {
const router = StackRouter(options);

return {
...router,
getStateForAction(state, action, options) {
const result = router.getStateForAction(state, action, options);

if (
result != null &&
result.index > state.index &&
state.routes[state.index].params?.isEditing
) {
// Returning the current state means that the action has been handled, but we don't have a new state
return state;
}

return result;
},
};
};

如果你想阻止返回,推荐的方法是使用 usePreventRemove hook