カスタムルーター
ルーターオブジェクトは、状態とアクションを処理するための様々なヘルパーメソッド、状態を更新するためのreducer、そしていくつかのアクションクリエイターを提供します。
ルーターは、navigationオブジェクトのメソッドを呼び出すことでディスパッチされたアクションの処理を担当します。ルーターがアクションを処理できない場合、`null`を返し、アクションが処理されるまで他のルーターに伝播させることができます。
以下の関数を持つオブジェクトを作成することで、独自のルーターを作成できます。
- `type` - ルーターの種類を表す文字列。例: `'stack'`、`'tab'`、`'drawer'`など。
- `getInitialState` - ナビゲーターの初期状態を返す関数。`routeNames`と`routeParamList`プロパティを持つオプションオブジェクトを受け取ります。
- `getRehydratedState` - 与えられた部分的な状態から完全なnavigation stateを再水和する関数。部分的な状態オブジェクトと、`routeNames`と`routeParamList`プロパティを持つオプションオブジェクトを受け取ります。
- `getStateForRouteNamesChange` - 現在の状態と更新されたルート名のリストを受け取り、新しい状態を返す関数。状態オブジェクトと、`routeNames`と`routeParamList`プロパティを持つオプションオブジェクトを受け取ります。
- `getStateForAction` - 現在の状態とアクション、そして`routeNames`と`routeParamList`プロパティを持つオプションオブジェクトを受け取り、新しい状態を返す関数。アクションを処理できない場合、`null`を返す必要があります。
- `getStateForRouteFocus` - 現在の状態とルートのキーを受け取り、そのルートがフォーカスされた新しい状態を返す関数。
- `shouldActionChangeFocus` - アクションが親ナビゲーターでフォーカスも変更する必要があるかどうかを決定する関数。`NAVIGATE`などのアクションは、親でフォーカスを変更する場合があります。
- `actionCreators` - `push`、`pop`などのアクションクリエイターのリストを含むオプションのオブジェクト。これらは、これらのアクションをディスパッチするためのヘルパーメソッドを`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`に関数を渡すことができます。ルーターをオーバーライドするよりもクリーンで推奨されます。
ナビゲーションアクションのブロック
ルートによっては、ナビゲーションアクティビティを防止したい場合があります。たとえば、`isEditing`が`true`の場合は、新しい画面のプッシュを防止したいとします。
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;
},
};
};
戻るのを防止したい場合は、`beforeRemove`イベントを使用することをお勧めします。