Skip to content
This repository was archived by the owner on Feb 8, 2020. It is now read-only.

Commit 1153d55

Browse files
committed
fix: fire blur event when a route is removed with a delay
closes #110
1 parent 76de32f commit 1153d55

File tree

2 files changed

+139
-13
lines changed

2 files changed

+139
-13
lines changed

packages/core/src/__tests__/useEventEmitter.test.tsx

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import useNavigationBuilder from '../useNavigationBuilder';
44
import NavigationContainer from '../NavigationContainer';
55
import Screen from '../Screen';
66
import MockRouter from './__fixtures__/MockRouter';
7+
import { Router, NavigationState } from '../types';
78

89
it('fires focus and blur events in root navigator', () => {
910
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
@@ -200,6 +201,131 @@ it('fires focus and blur events in nested navigator', () => {
200201
expect(thirdFocusCallback).toBeCalledTimes(1);
201202
});
202203

204+
it('fires blur event when a route is removed with a delay', async () => {
205+
const TestRouter = (options: any): Router<NavigationState, any> => {
206+
const router = MockRouter(options);
207+
208+
return {
209+
...router,
210+
211+
getInitialState({ routeNames, routeParamList }) {
212+
const initialRouteName =
213+
options.initialRouteName !== undefined
214+
? options.initialRouteName
215+
: routeNames[0];
216+
217+
return {
218+
stale: false,
219+
key: 'stack',
220+
index: 0,
221+
routeNames,
222+
routes: [
223+
{
224+
key: initialRouteName,
225+
name: initialRouteName,
226+
params: routeParamList[initialRouteName],
227+
},
228+
],
229+
};
230+
},
231+
232+
getStateForAction(state, action) {
233+
switch (action.type) {
234+
case 'PUSH':
235+
return {
236+
...state,
237+
index: state.index + 1,
238+
routes: [...state.routes, action.payload],
239+
};
240+
case 'POP': {
241+
const routes = state.routes.slice(0, -1);
242+
243+
return {
244+
...state,
245+
index: routes.length - 1,
246+
routes,
247+
};
248+
}
249+
default:
250+
return router.getStateForAction(state, action);
251+
}
252+
},
253+
254+
actionCreators: {
255+
push(payload) {
256+
return { type: 'PUSH', payload };
257+
},
258+
259+
pop() {
260+
return { type: 'POP' };
261+
},
262+
},
263+
};
264+
};
265+
266+
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
267+
const { state, navigation, descriptors } = useNavigationBuilder(
268+
TestRouter,
269+
props
270+
);
271+
272+
React.useImperativeHandle(ref, () => navigation, [navigation]);
273+
274+
const [previous, dispatch] = React.useReducer(
275+
(state, action) => {
276+
return { ...state, ...action };
277+
},
278+
{ routes: state.routes, descriptors }
279+
);
280+
281+
React.useEffect(() => {
282+
dispatch({ routes: state.routes, descriptors });
283+
}, [descriptors, state.routes]);
284+
285+
return previous.routes.map((route: any) =>
286+
previous.descriptors[route.key].render()
287+
);
288+
});
289+
290+
const blurCallback = jest.fn();
291+
292+
const First = () => null;
293+
294+
const Second = ({ navigation }: any) => {
295+
React.useEffect(() => navigation.addListener('blur', blurCallback), [
296+
navigation,
297+
]);
298+
299+
return null;
300+
};
301+
302+
const navigation = React.createRef<any>();
303+
304+
const element = (
305+
<NavigationContainer>
306+
<TestNavigator ref={navigation}>
307+
<Screen name="first" component={First} />
308+
<Screen name="second" component={Second} />
309+
</TestNavigator>
310+
</NavigationContainer>
311+
);
312+
313+
render(element);
314+
315+
act(() =>
316+
navigation.current.push({
317+
name: 'second',
318+
key: 'second',
319+
})
320+
);
321+
322+
expect(blurCallback).toBeCalledTimes(0);
323+
324+
act(() => navigation.current.pop());
325+
326+
expect(blurCallback).toBeCalledTimes(1);
327+
});
328+
203329
it('fires custom events', () => {
204330
const eventName = 'someSuperCoolEvent';
205331

packages/core/src/useFocusEvents.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,19 @@ export default function useFocusEvents({ state, emitter }: Options) {
5757
return;
5858
}
5959

60-
state.routes.forEach((route, i) => {
61-
if (
62-
lastFocusedKey === undefined ||
63-
(route.key !== lastFocusedKey && route.key !== currentFocusedKey)
64-
) {
65-
// Only fire events after mount, or if focus state of this route changed
66-
return;
67-
}
60+
if (lastFocusedKey === undefined) {
61+
// Only fire events after initial mount
62+
return;
63+
}
64+
65+
emitter.emit({
66+
type: 'focus',
67+
target: currentFocusedKey,
68+
});
6869

69-
emitter.emit({
70-
type: i === state.index ? 'focus' : 'blur',
71-
target: route.key,
72-
});
70+
emitter.emit({
71+
type: 'blur',
72+
target: lastFocusedKey,
7373
});
74-
}, [currentFocusedKey, emitter, navigation, state.index, state.routes]);
74+
}, [currentFocusedKey, emitter, navigation]);
7575
}

0 commit comments

Comments
 (0)