From 70c69307c459de7bdc16fcf3cf91034c5f38388f Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 22 Oct 2018 16:57:51 -0700 Subject: [PATCH] Add refocus event and fix child navigation caching --- packages/core/src/getChildEventSubscriber.js | 17 ++++ packages/core/src/getChildNavigation.js | 86 +++++++++---------- .../core/src/getChildrenNavigationCache.js | 17 ++++ packages/core/src/getNavigation.js | 2 + 4 files changed, 79 insertions(+), 43 deletions(-) create mode 100644 packages/core/src/getChildrenNavigationCache.js diff --git a/packages/core/src/getChildEventSubscriber.js b/packages/core/src/getChildEventSubscriber.js index 99c232e0..f6682429 100644 --- a/packages/core/src/getChildEventSubscriber.js +++ b/packages/core/src/getChildEventSubscriber.js @@ -10,6 +10,7 @@ export default function getChildEventSubscriber(addListener, key) { const didFocusSubscribers = new Set(); const willBlurSubscribers = new Set(); const didBlurSubscribers = new Set(); + const refocusSubscribers = new Set(); const removeAll = () => { [ @@ -18,6 +19,7 @@ export default function getChildEventSubscriber(addListener, key) { didFocusSubscribers, willBlurSubscribers, didBlurSubscribers, + refocusSubscribers, ].forEach(set => set.clear()); upstreamSubscribers.forEach(subs => subs && subs.remove()); @@ -35,6 +37,8 @@ export default function getChildEventSubscriber(addListener, key) { return willBlurSubscribers; case 'didBlur': return didBlurSubscribers; + case 'refocus': + return refocusSubscribers; default: return null; } @@ -60,11 +64,17 @@ export default function getChildEventSubscriber(addListener, key) { 'didFocus', 'willBlur', 'didBlur', + 'refocus', 'action', ]; const upstreamSubscribers = upstreamEvents.map(eventName => addListener(eventName, payload => { + if (eventName === 'refocus') { + emit(eventName, payload); + return; + } + const { state, lastState, action } = payload; const lastRoutes = lastState && lastState.routes; const routes = state && state.routes; @@ -157,5 +167,12 @@ export default function getChildEventSubscriber(addListener, key) { }; return { remove }; }, + emit(eventName, payload) { + if (eventName !== 'refocus') { + console.error(`navigation.emit only supports the 'refocus' event currently.`); + return; + } + emit(eventName, payload); + } }; } diff --git a/packages/core/src/getChildNavigation.js b/packages/core/src/getChildNavigation.js index ecc89723..205f10ae 100644 --- a/packages/core/src/getChildNavigation.js +++ b/packages/core/src/getChildNavigation.js @@ -1,6 +1,7 @@ import getChildEventSubscriber from './getChildEventSubscriber'; import getChildRouter from './getChildRouter'; import getNavigationActionCreators from './routers/getNavigationActionCreators'; +import getChildrenNavigationCache from './getChildrenNavigationCache'; const createParamGetter = route => (paramName, defaultValue) => { const params = route.params; @@ -13,9 +14,7 @@ const createParamGetter = route => (paramName, defaultValue) => { }; function getChildNavigation(navigation, childKey, getCurrentParentNavigation) { - const children = - navigation._childrenNavigation || (navigation._childrenNavigation = {}); - + const children = getChildrenNavigationCache(navigation); const childRoute = navigation.state.routes.find(r => r.key === childKey); if (!childRoute) { @@ -66,47 +65,48 @@ function getChildNavigation(navigation, childKey, getCurrentParentNavigation) { getParam: createParamGetter(childRoute), }; return children[childKey]; + } else { + const childSubscriber = getChildEventSubscriber( + navigation.addListener, + childKey + ); + + children[childKey] = { + ...actionHelpers, + + state: childRoute, + router: childRouter, + actions: actionCreators, + getParam: createParamGetter(childRoute), + + getChildNavigation: grandChildKey => + getChildNavigation(children[childKey], grandChildKey, () => { + const nav = getCurrentParentNavigation(); + return nav && nav.getChildNavigation(childKey); + }), + + isFocused: () => { + const currentNavigation = getCurrentParentNavigation(); + if (!currentNavigation) { + return false; + } + const { routes, index } = currentNavigation.state; + if (!currentNavigation.isFocused()) { + return false; + } + if (routes[index].key === childKey) { + return true; + } + return false; + }, + dispatch: navigation.dispatch, + getScreenProps: navigation.getScreenProps, + dangerouslyGetParent: getCurrentParentNavigation, + addListener: childSubscriber.addListener, + emit: childSubscriber.emit, + }; + return children[childKey]; } - - const childSubscriber = getChildEventSubscriber( - navigation.addListener, - childKey - ); - - children[childKey] = { - ...actionHelpers, - - state: childRoute, - router: childRouter, - actions: actionCreators, - getParam: createParamGetter(childRoute), - - getChildNavigation: grandChildKey => - getChildNavigation(children[childKey], grandChildKey, () => { - const nav = getCurrentParentNavigation(); - return nav && nav.getChildNavigation(childKey); - }), - - isFocused: () => { - const currentNavigation = getCurrentParentNavigation(); - if (!currentNavigation) { - return false; - } - const { routes, index } = currentNavigation.state; - if (!currentNavigation.isFocused()) { - return false; - } - if (routes[index].key === childKey) { - return true; - } - return false; - }, - dispatch: navigation.dispatch, - getScreenProps: navigation.getScreenProps, - dangerouslyGetParent: getCurrentParentNavigation, - addListener: childSubscriber.addListener, - }; - return children[childKey]; } export default getChildNavigation; diff --git a/packages/core/src/getChildrenNavigationCache.js b/packages/core/src/getChildrenNavigationCache.js new file mode 100644 index 00000000..f0c12336 --- /dev/null +++ b/packages/core/src/getChildrenNavigationCache.js @@ -0,0 +1,17 @@ +export default function getChildrenNavigationCache(navigation) { + if (!navigation) { + return {}; + } + + let childrenNavigationCache = navigation._childrenNavigation + ? navigation._childrenNavigation + : {}; + let childKeys = navigation.state.routes.map(route => route.key); + Object.keys(childrenNavigationCache).forEach(cacheKey => { + if (!childKeys.includes(cacheKey)) { + delete childrenNavigationCache[cacheKey]; + } + }); + + return childrenNavigationCache; +} diff --git a/packages/core/src/getNavigation.js b/packages/core/src/getNavigation.js index 236de18d..4ec67e00 100644 --- a/packages/core/src/getNavigation.js +++ b/packages/core/src/getNavigation.js @@ -1,5 +1,6 @@ import getNavigationActionCreators from './routers/getNavigationActionCreators'; import getChildNavigation from './getChildNavigation'; +import getChildrenNavigationCache from './getChildrenNavigationCache'; export default function getNavigation( router, @@ -38,6 +39,7 @@ export default function getNavigation( }; }, dangerouslyGetParent: () => null, + _childrenNavigation: getChildrenNavigationCache(getCurrentNavigation()) }; const actionCreators = {