fix: use correct dispatch in methods in screen's navigation prop

This commit is contained in:
satyajit.happy
2019-08-12 06:11:10 +05:30
parent 9625689595
commit 81348959ee
4 changed files with 60 additions and 40 deletions

View File

@@ -13,6 +13,7 @@ import {
NavigationState,
ParamListBase,
RouteConfig,
Router,
} from './types';
type Options<ScreenOptions extends object> = {
@@ -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;
};
@@ -54,6 +56,7 @@ export default function useDescriptors<
addActionListener,
removeActionListener,
onRouteFocus,
router,
emitter,
}: Options<ScreenOptions>) {
const [options, setOptions] = React.useState<{ [key: string]: object }>({});
@@ -79,6 +82,7 @@ export default function useDescriptors<
getState,
navigation,
setOptions,
router,
emitter,
});

View File

@@ -233,6 +233,7 @@ export default function useNavigationBuilder<
onRouteFocus,
addActionListener,
removeActionListener,
router,
emitter,
});

View File

@@ -1,4 +1,5 @@
import * as React from 'react';
import * as BaseActions from './BaseActions';
import { NavigationEventEmitter } from './useEventEmitter';
import {
NavigationAction,
@@ -6,15 +7,18 @@ import {
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;
};
@@ -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];
@@ -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,
@@ -86,7 +105,7 @@ export default function useNavigationCache<
return navigation ? navigation.isFocused() : true;
},
isFirstRouteInParent: () => isFirst,
} as NavigationProp<ParamListBase, string, State, ScreenOptions>;
};
}
return acc;

View File

@@ -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()));
@@ -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
@@ -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,