mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-28 20:35:19 +08:00
fix: use correct dispatch in methods in screen's navigation prop
This commit is contained in:
@@ -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,
|
||||
});
|
||||
|
||||
|
||||
@@ -233,6 +233,7 @@ export default function useNavigationBuilder<
|
||||
onRouteFocus,
|
||||
addActionListener,
|
||||
removeActionListener,
|
||||
router,
|
||||
emitter,
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user