Skip to content

Commit 44b2ace

Browse files
satya164osdnk
authored andcommitted
refactor: drop getStateForChildUpdate in favor of getStateForRouteFocus (facebook#15)
1 parent 3d8ba13 commit 44b2ace

File tree

12 files changed

+269
-306
lines changed

12 files changed

+269
-306
lines changed

example/StackNavigator.tsx

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ const StackRouter: Router<CommonAction | Action> = {
9696
};
9797
},
9898

99+
getStateForRouteFocus(state, key) {
100+
const index = state.routes.findIndex(r => r.key === key);
101+
102+
if (index === -1 || index === state.index) {
103+
return state;
104+
}
105+
106+
return {
107+
...state,
108+
index,
109+
routes: state.routes.slice(0, index + 1),
110+
};
111+
},
112+
99113
getStateForAction(state, action) {
100114
switch (action.type) {
101115
case 'PUSH':
@@ -219,27 +233,6 @@ const StackRouter: Router<CommonAction | Action> = {
219233
}
220234
},
221235

222-
getStateForChildUpdate(state, { update, focus, key }) {
223-
const index = state.routes.findIndex(r => r.key === key);
224-
225-
if (index === -1) {
226-
return state;
227-
}
228-
229-
return {
230-
...state,
231-
index: focus ? index : state.index,
232-
routes: focus
233-
? [
234-
...state.routes.slice(0, index),
235-
{ ...state.routes[index], state: update },
236-
]
237-
: state.routes.map((route, i) =>
238-
i === index ? { ...route, state: update } : route
239-
),
240-
};
241-
},
242-
243236
shouldActionPropagateToChildren(action) {
244237
return action.type === 'NAVIGATE';
245238
},

example/TabNavigator.tsx

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ const TabRouter: Router<Action | CommonAction> = {
8787
};
8888
},
8989

90+
getStateForRouteFocus(state, key) {
91+
const index = state.routes.findIndex(r => r.key === key);
92+
93+
if (index === -1) {
94+
return state;
95+
}
96+
97+
return { ...state, index };
98+
},
99+
90100
getStateForAction(state, action) {
91101
switch (action.type) {
92102
case 'JUMP_TO':
@@ -152,22 +162,6 @@ const TabRouter: Router<Action | CommonAction> = {
152162
}
153163
},
154164

155-
getStateForChildUpdate(state, { update, focus, key }) {
156-
const index = state.routes.findIndex(r => r.key === key);
157-
158-
if (index === -1) {
159-
return state;
160-
}
161-
162-
return {
163-
...state,
164-
index: focus ? index : state.index,
165-
routes: state.routes.map((route, i) =>
166-
i === index ? { ...route, state: update } : route
167-
),
168-
};
169-
},
170-
171165
shouldActionPropagateToChildren(action) {
172166
return action.type === 'NAVIGATE';
173167
},

src/NavigationBuilderContext.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import { NavigationHelpers, NavigationAction, NavigationState } from './types';
2+
import { NavigationHelpers, NavigationAction } from './types';
33

44
export type ChildActionListener = (
55
action: NavigationAction,
@@ -11,11 +11,7 @@ const NavigationBuilderContext = React.createContext<{
1111
onAction?: (action: NavigationAction, sourceNavigatorKey?: string) => boolean;
1212
addActionListener?: (listener: ChildActionListener) => void;
1313
removeActionListener?: (listener: ChildActionListener) => void;
14-
onChildUpdate?: (
15-
state: NavigationState,
16-
focus: boolean,
17-
key: string | undefined
18-
) => void;
14+
onRouteFocus?: (key: string) => void;
1915
}>({});
2016

2117
export default NavigationBuilderContext;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { Router } from '../../types';
2+
3+
const MockRouter: Router<{ type: string }> & { key: number } = {
4+
key: 0,
5+
6+
getInitialState({
7+
routeNames,
8+
initialRouteName = routeNames[0],
9+
initialParamsList,
10+
}) {
11+
const index = routeNames.indexOf(initialRouteName);
12+
13+
return {
14+
key: String(MockRouter.key++),
15+
index,
16+
routeNames,
17+
routes: routeNames.map(name => ({
18+
name,
19+
key: name,
20+
params: initialParamsList[name],
21+
})),
22+
};
23+
},
24+
25+
getRehydratedState({ routeNames, partialState }) {
26+
let state = partialState;
27+
28+
if (state.routeNames === undefined || state.key === undefined) {
29+
state = {
30+
...state,
31+
routeNames,
32+
key: String(MockRouter.key++),
33+
};
34+
}
35+
36+
return state;
37+
},
38+
39+
getStateForRouteNamesChange(state, { routeNames }) {
40+
return {
41+
...state,
42+
routeNames,
43+
routes: state.routes.filter(route => routeNames.includes(route.name)),
44+
};
45+
},
46+
47+
getStateForRouteFocus(state, key) {
48+
const index = state.routes.findIndex(r => r.key === key);
49+
50+
if (index === -1 || index === state.index) {
51+
return state;
52+
}
53+
54+
return { ...state, index };
55+
},
56+
57+
getStateForAction(state, action) {
58+
switch (action.type) {
59+
case 'UPDATE':
60+
return { ...state };
61+
62+
case 'NOOP':
63+
return state;
64+
65+
default:
66+
return null;
67+
}
68+
},
69+
70+
shouldActionPropagateToChildren() {
71+
return false;
72+
},
73+
74+
shouldActionChangeFocus() {
75+
return false;
76+
},
77+
78+
actionCreators: {},
79+
};
80+
81+
export default MockRouter;

src/__tests__/index.test.tsx

Lines changed: 1 addition & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -3,91 +3,7 @@ import { render, act } from 'react-native-testing-library';
33
import Screen from '../Screen';
44
import NavigationContainer from '../NavigationContainer';
55
import useNavigationBuilder from '../useNavigationBuilder';
6-
import { Router } from '../types';
7-
8-
export const MockRouter: Router<{ type: string }> & { key: number } = {
9-
key: 0,
10-
11-
getInitialState({
12-
routeNames,
13-
initialRouteName = routeNames[0],
14-
initialParamsList,
15-
}) {
16-
const index = routeNames.indexOf(initialRouteName);
17-
18-
return {
19-
key: String(MockRouter.key++),
20-
index,
21-
routeNames,
22-
routes: routeNames.map(name => ({
23-
name,
24-
key: name,
25-
params: initialParamsList[name],
26-
})),
27-
};
28-
},
29-
30-
getRehydratedState({ routeNames, partialState }) {
31-
let state = partialState;
32-
33-
if (state.routeNames === undefined || state.key === undefined) {
34-
state = {
35-
...state,
36-
routeNames,
37-
key: String(MockRouter.key++),
38-
};
39-
}
40-
41-
return state;
42-
},
43-
44-
getStateForRouteNamesChange(state, { routeNames }) {
45-
return {
46-
...state,
47-
routeNames,
48-
routes: state.routes.filter(route => routeNames.includes(route.name)),
49-
};
50-
},
51-
52-
getStateForAction(state, action) {
53-
switch (action.type) {
54-
case 'UPDATE':
55-
return { ...state };
56-
57-
case 'NOOP':
58-
return state;
59-
60-
default:
61-
return null;
62-
}
63-
},
64-
65-
getStateForChildUpdate(state, { update, focus, key }) {
66-
const index = state.routes.findIndex(r => r.key === key);
67-
68-
if (index === -1) {
69-
return state;
70-
}
71-
72-
return {
73-
...state,
74-
index: focus ? index : state.index,
75-
routes: state.routes.map((route, i) =>
76-
i === index ? { ...route, state: update } : route
77-
),
78-
};
79-
},
80-
81-
shouldActionPropagateToChildren() {
82-
return false;
83-
},
84-
85-
shouldActionChangeFocus() {
86-
return false;
87-
},
88-
89-
actionCreators: {},
90-
};
6+
import MockRouter from './__fixtures__/MockRouter';
917

928
beforeEach(() => (MockRouter.key = 0));
939

@@ -399,75 +315,6 @@ it('cleans up state when the navigator unmounts', () => {
399315
expect(onStateChange).lastCalledWith(undefined);
400316
});
401317

402-
it("lets parent handle the action if child didn't", () => {
403-
const ParentRouter: Router<{ type: string }> = {
404-
...MockRouter,
405-
406-
getStateForAction(state, action) {
407-
if (action.type === 'REVERSE') {
408-
return {
409-
...state,
410-
routes: state.routes.slice().reverse(),
411-
};
412-
}
413-
414-
return MockRouter.getStateForAction(state, action);
415-
},
416-
};
417-
418-
const ParentNavigator = (props: any) => {
419-
const { state, descriptors } = useNavigationBuilder(ParentRouter, props);
420-
421-
return descriptors[state.routes[state.index].key].render();
422-
};
423-
424-
const ChildNavigator = (props: any) => {
425-
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
426-
427-
return descriptors[state.routes[state.index].key].render();
428-
};
429-
430-
const TestScreen = (props: any) => {
431-
React.useEffect(() => {
432-
props.navigation.dispatch({ type: 'REVERSE' });
433-
434-
// eslint-disable-next-line react-hooks/exhaustive-deps
435-
}, []);
436-
437-
return null;
438-
};
439-
440-
const onStateChange = jest.fn();
441-
442-
render(
443-
<NavigationContainer onStateChange={onStateChange}>
444-
<ParentNavigator initialRouteName="baz">
445-
<Screen name="foo">{() => null}</Screen>
446-
<Screen name="bar">{() => null}</Screen>
447-
<Screen name="baz">
448-
{() => (
449-
<ChildNavigator>
450-
<Screen name="qux" component={TestScreen} />
451-
</ChildNavigator>
452-
)}
453-
</Screen>
454-
</ParentNavigator>
455-
</NavigationContainer>
456-
);
457-
458-
expect(onStateChange).toBeCalledTimes(1);
459-
expect(onStateChange).lastCalledWith({
460-
index: 2,
461-
key: '0',
462-
routeNames: ['foo', 'bar', 'baz'],
463-
routes: [
464-
{ key: 'baz', name: 'baz' },
465-
{ key: 'bar', name: 'bar' },
466-
{ key: 'foo', name: 'foo' },
467-
],
468-
});
469-
});
470-
471318
it('allows arbitrary state updates by dispatching a function', () => {
472319
const TestNavigator = (props: any) => {
473320
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

0 commit comments

Comments
 (0)