feat: handle navigating with both with both key and name (#83)

This commit is contained in:
Michał Osadnik
2019-08-29 08:46:51 +01:00
committed by Satyajit Sahoo
parent c951027ebb
commit 6b75cbaaa6
5 changed files with 71 additions and 50 deletions

View File

@@ -10,7 +10,8 @@ export type Action =
type: 'NAVIGATE';
payload:
| { name: string; key?: undefined; params?: object }
| { key: string; name?: undefined; params?: object };
| { key: string; name?: undefined; params?: object }
| { key: string; name: string; params?: object };
source?: string;
target?: string;
}
@@ -38,7 +39,10 @@ export function goBack(): Action {
}
export function navigate(
route: { key: string; params?: object } | { name: string; params?: object }
route:
| { key: string; params?: object }
| { name: string; params?: object }
| { name: string; key: string; params?: object }
): Action;
export function navigate(name: string, params?: object): Action;
export function navigate(...args: any): Action {
@@ -47,12 +51,9 @@ export function navigate(...args: any): Action {
} else {
const payload = args[0];
if (
(payload.hasOwnProperty('key') && payload.hasOwnProperty('name')) ||
(!payload.hasOwnProperty('key') && !payload.hasOwnProperty('name'))
) {
if (!payload.hasOwnProperty('key') && !payload.hasOwnProperty('name')) {
throw new Error(
'While calling navigate with an object as the argument, you need to specify either name or key'
'While calling navigate with an object as the argument, you need to specify name or key'
);
}

View File

@@ -7,42 +7,7 @@ import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
beforeEach(() => (MockRouterKey.current = 0));
it('throws if NAVIGATE dispatched with both key and name', () => {
const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
return descriptors[state.routes[state.index].key].render();
};
const FooScreen = (props: any) => {
React.useEffect(() => {
props.navigation.navigate({ key: '1', name: '2' });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
};
const onStateChange = jest.fn();
const element = (
<NavigationContainer onStateChange={onStateChange}>
<TestNavigator initialRouteName="foo">
<Screen
name="foo"
component={FooScreen}
initialParams={{ count: 10 }}
/>
</TestNavigator>
</NavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
'While calling navigate with an object as the argument, you need to specify either name or key'
);
});
it('throws if NAVIGATE dispatched neither both key nor name', () => {
it('throws if NAVIGATE dispatched neither key nor name', () => {
const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
@@ -73,6 +38,6 @@ it('throws if NAVIGATE dispatched neither both key nor name', () => {
);
expect(() => render(element).update(element)).toThrowError(
'While calling navigate with an object as the argument, you need to specify either name or key'
'While calling navigate with an object as the argument, you need to specify name or key'
);
});

View File

@@ -287,7 +287,7 @@ type NavigationHelpersCommon<
navigate<RouteName extends keyof ParamList>(
route:
| { key: string; params?: ParamList[RouteName] }
| { name: RouteName; params: ParamList[RouteName] }
| { name: RouteName; key?: string; params: ParamList[RouteName] }
): void;
/**

View File

@@ -267,6 +267,51 @@ it('handles navigate action', () => {
CommonActions.navigate({ key: 'unknown' })
)
).toBe(null);
expect(
router.getStateForAction(
{
stale: false,
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz-0', name: 'baz' }, { key: 'bar', name: 'bar' }],
},
{
type: 'NAVIGATE',
payload: { key: 'baz-0', name: 'baz' },
}
)
).toEqual({
stale: false,
key: 'root',
index: 0,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz-0', name: 'baz' }],
});
expect(
router.getStateForAction(
{
stale: false,
key: 'root',
index: 1,
routeNames: ['baz', 'bar', 'qux'],
routes: [{ key: 'baz-0', name: 'baz' }, { key: 'bar', name: 'bar' }],
},
CommonActions.navigate({ key: 'baz-1', name: 'baz' })
)
).toEqual({
stale: false,
key: 'root',
index: 2,
routeNames: ['baz', 'bar', 'qux'],
routes: [
{ key: 'baz-0', name: 'baz' },
{ key: 'bar', name: 'bar' },
{ key: 'baz-1', name: 'baz' },
],
});
});
it('handles go back action', () => {

View File

@@ -11,7 +11,7 @@ import {
export type StackActionType =
| {
type: 'PUSH';
payload: { name: string; params?: object };
payload: { name: string; key?: string | undefined; params?: object };
source?: string;
target?: string;
}
@@ -151,7 +151,10 @@ export default function StackRouter(options: StackRouterOptions) {
routes: [
...state.routes,
{
key: `${action.payload.name}-${shortid()}`,
key:
action.payload.key === undefined
? `${action.payload.name}-${shortid()}`
: action.payload.key,
name: action.payload.name,
params: action.payload.params,
},
@@ -199,14 +202,16 @@ export default function StackRouter(options: StackRouterOptions) {
let index = -1;
if (
state.routes[state.index].name === action.payload.name ||
(state.routes[state.index].name === action.payload.name &&
action.payload.key === undefined) ||
state.routes[state.index].key === action.payload.key
) {
index = state.index;
} else {
for (let i = state.routes.length - 1; i >= 0; i--) {
if (
state.routes[i].name === action.payload.name ||
(state.routes[i].name === action.payload.name &&
action.payload.key === undefined) ||
state.routes[i].key === action.payload.key
) {
index = i;
@@ -215,7 +220,11 @@ export default function StackRouter(options: StackRouterOptions) {
}
}
if (index === -1 && action.payload.key) {
if (
index === -1 &&
action.payload.key &&
action.payload.name === undefined
) {
return null;
}
@@ -223,6 +232,7 @@ export default function StackRouter(options: StackRouterOptions) {
return router.getStateForAction(state, {
type: 'PUSH',
payload: {
key: action.payload.key,
name: action.payload.name,
params: action.payload.params,
},