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

Commit

Permalink
fix: use correct dispatch in methods in screen's navigation prop
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Aug 12, 2019
1 parent 9625689 commit 8134895
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 40 deletions.
4 changes: 4 additions & 0 deletions packages/core/src/useDescriptors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
NavigationState,
ParamListBase,
RouteConfig,
Router,
} from './types';

type Options<ScreenOptions extends object> = {
Expand All @@ -29,6 +30,7 @@ type Options<ScreenOptions extends object> = {
addActionListener: (listener: ChildActionListener) => void;
removeActionListener: (listener: ChildActionListener) => void;
onRouteFocus: (key: string) => void;
router: Router<NavigationState, NavigationAction>;
emitter: NavigationEventEmitter;
};

Expand All @@ -54,6 +56,7 @@ export default function useDescriptors<
addActionListener,
removeActionListener,
onRouteFocus,
router,
emitter,
}: Options<ScreenOptions>) {
const [options, setOptions] = React.useState<{ [key: string]: object }>({});
Expand All @@ -79,6 +82,7 @@ export default function useDescriptors<
getState,
navigation,
setOptions,
router,
emitter,
});

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/useNavigationBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export default function useNavigationBuilder<
onRouteFocus,
addActionListener,
removeActionListener,
router,
emitter,
});

Expand Down
47 changes: 33 additions & 14 deletions packages/core/src/useNavigationCache.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import * as React from 'react';
import * as BaseActions from './BaseActions';
import { NavigationEventEmitter } from './useEventEmitter';
import {
NavigationAction,
NavigationHelpers,
NavigationProp,
ParamListBase,
NavigationState,
Router,
} from './types';

type Options = {
state: NavigationState;
getState: () => NavigationState;
navigation: NavigationHelpers<ParamListBase>;
navigation: NavigationHelpers<ParamListBase> &
Partial<NavigationProp<ParamListBase, string, any, any, any>>;
setOptions: (
cb: (options: { [key: string]: object }) => { [key: string]: object }
) => void;
router: Router<NavigationState, NavigationAction>;
emitter: NavigationEventEmitter;
};

Expand All @@ -33,16 +37,21 @@ type NavigationCache<
export default function useNavigationCache<
State extends NavigationState,
ScreenOptions extends object
>({ state, getState, navigation, setOptions, emitter }: Options) {
>({ state, getState, navigation, setOptions, router, emitter }: Options) {
// Cache object which holds navigation objects for each screen
// We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
// In reality, these deps will rarely change, if ever
const cache = React.useMemo(
() => ({ current: {} as NavigationCache<State, ScreenOptions> }),
// eslint-disable-next-line react-hooks/exhaustive-deps
[getState, navigation, setOptions, emitter]
[getState, navigation, setOptions, router, emitter]
);

const actions = {
...router.actionCreators,
...BaseActions,
};

cache.current = state.routes.reduce<NavigationCache<State, ScreenOptions>>(
(acc, route, index) => {
const previous = cache.current[route.key];
Expand All @@ -56,19 +65,29 @@ export default function useNavigationCache<
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { emit, ...rest } = navigation;

const dispatch = (
action: NavigationAction | ((state: State) => State)
) =>
navigation.dispatch(
typeof action === 'object' && action != null
? { source: route.key, ...action }
: action
);

const helpers = Object.keys(actions).reduce(
(acc, name) => {
// @ts-ignore
acc[name] = (...args: any) => dispatch(actions[name](...args));
return acc;
},
{} as { [key: string]: () => void }
);

acc[route.key] = {
...rest,
...helpers,
...emitter.create(route.key),
dispatch: (
action:
| NavigationAction
| ((state: NavigationState) => NavigationState)
) =>
navigation.dispatch(
typeof action === 'object' && action != null
? { source: route.key, ...action }
: action
),
dispatch,
setOptions: (options: object) =>
setOptions(o => ({
...o,
Expand All @@ -86,7 +105,7 @@ export default function useNavigationCache<
return navigation ? navigation.isFocused() : true;
},
isFirstRouteInParent: () => isFirst,
} as NavigationProp<ParamListBase, string, State, ScreenOptions>;
};
}

return acc;
Expand Down
48 changes: 22 additions & 26 deletions packages/core/src/useNavigationHelpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,30 @@ import {
Router,
} from './types';

type Options<Action extends NavigationAction> = {
type Options<State extends NavigationState, Action extends NavigationAction> = {
onAction: (
action: NavigationAction,
visitedNavigators?: Set<string>
) => boolean;
getState: () => NavigationState;
setState: (state: NavigationState) => void;
getState: () => State;
setState: (state: State) => void;
emitter: NavigationEventEmitter;
router: Router<NavigationState, Action>;
router: Router<State, Action>;
};

/**
* Navigation object with helper methods to be used by a navigator.
* This object includes methods for common actions as well as methods the parent screen's navigation object.
*/
export default function useNavigationHelpers<Action extends NavigationAction>({
onAction,
getState,
setState,
emitter,
router,
}: Options<Action>) {
export default function useNavigationHelpers<
State extends NavigationState,
Action extends NavigationAction
>({ onAction, getState, setState, emitter, router }: Options<State, Action>) {
const parentNavigationHelpers = React.useContext(NavigationContext);
const { performTransaction } = React.useContext(NavigationStateContext);

return React.useMemo((): NavigationHelpers<ParamListBase> &
Partial<NavigationProp<ParamListBase, string, any, any, any>> => {
const dispatch = (
action: NavigationAction | ((state: NavigationState) => NavigationState)
) => {
return React.useMemo(() => {
const dispatch = (action: Action | ((state: State) => State)) => {
performTransaction(() => {
if (typeof action === 'function') {
setState(action(getState()));
Expand All @@ -56,17 +50,18 @@ export default function useNavigationHelpers<Action extends NavigationAction>({
...BaseActions,
};

// @ts-ignore
const helpers = Object.keys(actions).reduce(
(acc, name) => {
// @ts-ignore
acc[name] = (...args: any) => dispatch(actions[name](...args));
return acc;
},
{} as { [key: string]: () => void }
);

return {
...parentNavigationHelpers,
...Object.keys(actions).reduce(
(acc, name) => {
// @ts-ignore
acc[name] = (...args: any) => dispatch(actions[name](...args));
return acc;
},
{} as { [key: string]: () => void }
),
...helpers,
dispatch,
emit: emitter.emit,
isFocused: parentNavigationHelpers
Expand All @@ -76,7 +71,8 @@ export default function useNavigationHelpers<Action extends NavigationAction>({
router.canGoBack(getState()) ||
(parentNavigationHelpers && parentNavigationHelpers.canGoBack()) ||
false,
};
} as NavigationHelpers<ParamListBase> &
(NavigationProp<ParamListBase, string, any, any, any> | undefined);
}, [
router,
getState,
Expand Down

0 comments on commit 8134895

Please sign in to comment.