mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-10 22:47:02 +08:00
feat: add target argument to setParams (#18)
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
CommonAction,
|
||||
ParamListBase,
|
||||
Router,
|
||||
BaseRouter,
|
||||
createNavigator,
|
||||
} from '../src/index';
|
||||
|
||||
@@ -28,9 +29,8 @@ type Action =
|
||||
| { type: 'POP_TO_TOP' };
|
||||
|
||||
export type StackNavigationProp<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList = string
|
||||
> = NavigationProp<ParamList, RouteName> & {
|
||||
ParamList extends ParamListBase
|
||||
> = NavigationProp<ParamList> & {
|
||||
/**
|
||||
* Push a new screen onto the stack.
|
||||
*
|
||||
@@ -55,6 +55,7 @@ export type StackNavigationProp<
|
||||
};
|
||||
|
||||
const StackRouter: Router<CommonAction | Action> = {
|
||||
...BaseRouter,
|
||||
getInitialState({
|
||||
routeNames,
|
||||
initialRouteName = routeNames[0],
|
||||
@@ -88,14 +89,6 @@ const StackRouter: Router<CommonAction | Action> = {
|
||||
return state;
|
||||
},
|
||||
|
||||
getStateForRouteNamesChange(state, { routeNames }) {
|
||||
return {
|
||||
...state,
|
||||
routeNames,
|
||||
routes: state.routes.filter(route => routeNames.includes(route.name)),
|
||||
};
|
||||
},
|
||||
|
||||
getStateForRouteFocus(state, key) {
|
||||
const index = state.routes.findIndex(r => r.key === key);
|
||||
|
||||
@@ -246,18 +239,10 @@ const StackRouter: Router<CommonAction | Action> = {
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
return BaseRouter.getStateForAction(state, action);
|
||||
}
|
||||
},
|
||||
|
||||
shouldActionPropagateToChildren(action) {
|
||||
return action.type === 'NAVIGATE';
|
||||
},
|
||||
|
||||
shouldActionChangeFocus(action) {
|
||||
return action.type === 'NAVIGATE';
|
||||
},
|
||||
|
||||
actionCreators: {
|
||||
push(name: string, params?: object) {
|
||||
return { type: 'PUSH', payload: { name, params } };
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Router,
|
||||
createNavigator,
|
||||
TargetRoute,
|
||||
BaseRouter,
|
||||
} from '../src/index';
|
||||
|
||||
type Props = {
|
||||
@@ -22,10 +23,9 @@ type Action = {
|
||||
payload: { name?: string; key?: string; params?: object };
|
||||
};
|
||||
|
||||
export type TabNavigationProp<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList = string
|
||||
> = NavigationProp<ParamList, RouteName> & {
|
||||
export type TabNavigationProp<ParamList extends ParamListBase> = NavigationProp<
|
||||
ParamList
|
||||
> & {
|
||||
/**
|
||||
* Jump to an existing tab.
|
||||
*
|
||||
@@ -168,7 +168,7 @@ const TabRouter: Router<Action | CommonAction> = {
|
||||
return null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
return BaseRouter.getStateForAction(state, action);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
NavigationContainer,
|
||||
CompositeNavigationProp,
|
||||
PartialState,
|
||||
NavigationHelpers,
|
||||
NavigationProp,
|
||||
RouteProp,
|
||||
} from '../src';
|
||||
import StackNavigator, { StackNavigationProp } from './StackNavigator';
|
||||
@@ -30,8 +30,8 @@ const First = ({
|
||||
route,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
StackNavigationProp<StackParamList, 'first'>,
|
||||
NavigationHelpers<TabParamList>
|
||||
StackNavigationProp<StackParamList>,
|
||||
NavigationProp<TabParamList>
|
||||
>;
|
||||
route: RouteProp<StackParamList, 'first'>;
|
||||
}) => (
|
||||
@@ -62,8 +62,8 @@ const Second = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
StackNavigationProp<StackParamList, 'second'>,
|
||||
NavigationHelpers<TabParamList>
|
||||
StackNavigationProp<StackParamList>,
|
||||
NavigationProp<TabParamList>
|
||||
>;
|
||||
}) => (
|
||||
<div>
|
||||
@@ -84,7 +84,7 @@ const Fourth = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
TabNavigationProp<TabParamList, 'fourth'>,
|
||||
TabNavigationProp<TabParamList>,
|
||||
StackNavigationProp<StackParamList>
|
||||
>;
|
||||
}) => (
|
||||
@@ -109,7 +109,7 @@ const Fifth = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: CompositeNavigationProp<
|
||||
TabNavigationProp<TabParamList, 'fifth'>,
|
||||
TabNavigationProp<TabParamList>,
|
||||
StackNavigationProp<StackParamList>
|
||||
>;
|
||||
}) => (
|
||||
|
||||
@@ -13,6 +13,10 @@ export type Action =
|
||||
| {
|
||||
type: 'RESET';
|
||||
payload: PartialState & { key?: string };
|
||||
}
|
||||
| {
|
||||
type: 'SET_PARAMS';
|
||||
payload: { name?: string; key?: string; params?: object };
|
||||
};
|
||||
|
||||
export function goBack(): Action {
|
||||
@@ -20,17 +24,17 @@ export function goBack(): Action {
|
||||
}
|
||||
|
||||
export function navigate(target: TargetRoute<string>, params?: object): Action {
|
||||
if (
|
||||
(target.hasOwnProperty('key') && target.hasOwnProperty('name')) ||
|
||||
(!target.hasOwnProperty('key') && !target.hasOwnProperty('name'))
|
||||
) {
|
||||
throw new Error(
|
||||
'While calling navigate you need to specify either name or key'
|
||||
);
|
||||
}
|
||||
if (typeof target === 'string') {
|
||||
return { type: 'NAVIGATE', payload: { name: target, params } };
|
||||
} else {
|
||||
if (
|
||||
(target.hasOwnProperty('key') && target.hasOwnProperty('name')) ||
|
||||
(!target.hasOwnProperty('key') && !target.hasOwnProperty('name'))
|
||||
) {
|
||||
throw new Error(
|
||||
'While calling navigate you need to specify either name or key'
|
||||
);
|
||||
}
|
||||
return { type: 'NAVIGATE', payload: { ...target, params } };
|
||||
}
|
||||
}
|
||||
@@ -42,3 +46,20 @@ export function replace(name: string, params?: object): Action {
|
||||
export function reset(state: PartialState & { key?: string }): Action {
|
||||
return { type: 'RESET', payload: state };
|
||||
}
|
||||
|
||||
export function setParams(
|
||||
params: object,
|
||||
target: { name?: string; key?: string }
|
||||
): Action {
|
||||
if (
|
||||
target &&
|
||||
((target.hasOwnProperty('key') && target.hasOwnProperty('name')) ||
|
||||
(!target.hasOwnProperty('key') && !target.hasOwnProperty('name')))
|
||||
) {
|
||||
throw new Error(
|
||||
'While calling setState with given second param you need to specify either name or key'
|
||||
);
|
||||
}
|
||||
|
||||
return { type: 'SET_PARAMS', payload: { params, ...target } };
|
||||
}
|
||||
|
||||
49
src/BaseRouter.tsx
Normal file
49
src/BaseRouter.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { CommonAction, Router } from './types';
|
||||
|
||||
const BaseRouter: Omit<
|
||||
Omit<Router<CommonAction>, 'getInitialState'>,
|
||||
'getRehydratedState'
|
||||
> = {
|
||||
getStateForAction(state, action) {
|
||||
switch (action.type) {
|
||||
case 'SET_PARAMS':
|
||||
return {
|
||||
...state,
|
||||
routes: state.routes.map(r =>
|
||||
r.key === action.payload.key || r.name === action.payload.name
|
||||
? { ...r, params: { ...r.params, ...action.payload.params } }
|
||||
: r
|
||||
),
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
getStateForRouteNamesChange(state, { routeNames }) {
|
||||
return {
|
||||
...state,
|
||||
routeNames,
|
||||
routes: state.routes.filter(route => routeNames.includes(route.name)),
|
||||
};
|
||||
},
|
||||
|
||||
getStateForRouteFocus(state, key) {
|
||||
const index = state.routes.findIndex(r => r.key === key);
|
||||
|
||||
if (index === -1 || index === state.index) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return { ...state, index };
|
||||
},
|
||||
shouldActionPropagateToChildren(action) {
|
||||
return action.type === 'NAVIGATE';
|
||||
},
|
||||
|
||||
shouldActionChangeFocus(action) {
|
||||
return action.type === 'NAVIGATE';
|
||||
},
|
||||
};
|
||||
|
||||
export default BaseRouter;
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { NavigationHelpers, NavigationAction } from './types';
|
||||
import { NavigationProp, NavigationAction } from './types';
|
||||
|
||||
export type ChildActionListener = (
|
||||
action: NavigationAction,
|
||||
@@ -7,7 +7,7 @@ export type ChildActionListener = (
|
||||
) => boolean;
|
||||
|
||||
const NavigationBuilderContext = React.createContext<{
|
||||
navigation?: NavigationHelpers;
|
||||
navigation?: NavigationProp;
|
||||
onAction?: (action: NavigationAction, sourceNavigatorKey?: string) => boolean;
|
||||
addActionListener?: (listener: ChildActionListener) => void;
|
||||
removeActionListener?: (listener: ChildActionListener) => void;
|
||||
|
||||
@@ -4,14 +4,15 @@ import StaticContainer from './StaticContainer';
|
||||
import {
|
||||
Route,
|
||||
NavigationState,
|
||||
NavigationHelpers,
|
||||
NavigationProp,
|
||||
RouteConfig,
|
||||
TargetRoute,
|
||||
} from './types';
|
||||
import EnsureSingleNavigator from './EnsureSingleNavigator';
|
||||
|
||||
type Props = {
|
||||
screen: RouteConfig;
|
||||
navigation: NavigationHelpers;
|
||||
navigation: NavigationProp;
|
||||
route: Route & { state?: NavigationState };
|
||||
getState: () => NavigationState;
|
||||
setState: (state: NavigationState) => void;
|
||||
@@ -24,22 +25,11 @@ export default function SceneView(props: Props) {
|
||||
const navigation = React.useMemo(
|
||||
() => ({
|
||||
...helpers,
|
||||
setParams: (params: object) => {
|
||||
performTransaction(() => {
|
||||
const state = getState();
|
||||
|
||||
setState({
|
||||
...state,
|
||||
routes: state.routes.map(r =>
|
||||
r.key === route.key
|
||||
? { ...r, params: { ...r.params, ...params } }
|
||||
: r
|
||||
),
|
||||
});
|
||||
});
|
||||
setParams: (params: object, target?: TargetRoute<string>) => {
|
||||
helpers.setParams(params, target ? target : { key: route.key });
|
||||
},
|
||||
}),
|
||||
[getState, helpers, performTransaction, route.key, setState]
|
||||
[helpers, route.key]
|
||||
);
|
||||
|
||||
const getCurrentState = React.useCallback(() => {
|
||||
|
||||
@@ -76,3 +76,73 @@ it('throws if NAVIGATE dispatched neither both key nor name', () => {
|
||||
'While calling navigate you need to specify either name or key'
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if SET_PARAMS dispatched with both key and name', () => {
|
||||
const TestNavigator = (props: any) => {
|
||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||
|
||||
return descriptors[state.routes[state.index].key].render();
|
||||
};
|
||||
|
||||
const FooScreen = (props: any) => {
|
||||
React.useEffect(() => {
|
||||
props.navigation.setParams({}, { key: '1', name: '2' });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const onStateChange = jest.fn();
|
||||
|
||||
const element = (
|
||||
<NavigationContainer onStateChange={onStateChange}>
|
||||
<TestNavigator initialRouteName="foo">
|
||||
<Screen
|
||||
name="foo"
|
||||
component={FooScreen}
|
||||
initialParams={{ count: 10 }}
|
||||
/>
|
||||
</TestNavigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
'While calling setState with given second param you need to specify either name or key'
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if SET_PARAMS dispatched neither both key nor name', () => {
|
||||
const TestNavigator = (props: any) => {
|
||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||
|
||||
return descriptors[state.routes[state.index].key].render();
|
||||
};
|
||||
|
||||
const FooScreen = (props: any) => {
|
||||
React.useEffect(() => {
|
||||
props.navigation.setParams({}, {});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const onStateChange = jest.fn();
|
||||
|
||||
const element = (
|
||||
<NavigationContainer onStateChange={onStateChange}>
|
||||
<TestNavigator initialRouteName="foo">
|
||||
<Screen
|
||||
name="foo"
|
||||
component={FooScreen}
|
||||
initialParams={{ count: 10 }}
|
||||
/>
|
||||
</TestNavigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
expect(() => render(element).update(element)).toThrowError(
|
||||
'While calling setState with given second param you need to specify either name or key'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { Router } from '../../types';
|
||||
import { Router, CommonAction } from '../../types';
|
||||
import { BaseRouter } from '../../index';
|
||||
|
||||
const MockRouter: Router<{ type: string }> & { key: number } = {
|
||||
export type MockActions = CommonAction & { type: 'NOOP' | 'REVERSE' | 'UPDATE' };
|
||||
|
||||
const MockRouter: Router<MockActions> & { key: number } = {
|
||||
key: 0,
|
||||
|
||||
getInitialState({
|
||||
@@ -63,7 +66,7 @@ const MockRouter: Router<{ type: string }> & { key: number } = {
|
||||
return state;
|
||||
|
||||
default:
|
||||
return null;
|
||||
return BaseRouter.getStateForAction(state, action);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -412,6 +412,56 @@ it('updates route params with setParams', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('updates another route params with setParams', () => {
|
||||
const TestNavigator = (props: any) => {
|
||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||
|
||||
return descriptors[state.routes[state.index].key].render();
|
||||
};
|
||||
|
||||
let setParams: (params: object, target: object) => void = () => undefined;
|
||||
|
||||
const FooScreen = (props: any) => {
|
||||
setParams = props.navigation.setParams;
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const onStateChange = jest.fn();
|
||||
|
||||
render(
|
||||
<NavigationContainer onStateChange={onStateChange}>
|
||||
<TestNavigator initialRouteName="foo">
|
||||
<Screen name="foo" component={FooScreen} />
|
||||
<Screen name="bar" component={jest.fn()} />
|
||||
</TestNavigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
act(() => setParams({ username: 'alice' }, { name: 'bar' }));
|
||||
|
||||
expect(onStateChange).toBeCalledTimes(1);
|
||||
expect(onStateChange).lastCalledWith({
|
||||
index: 0,
|
||||
key: '0',
|
||||
routeNames: ['foo', 'bar'],
|
||||
routes: [{ key: 'foo', name: 'foo', params: undefined }, { key: 'bar', name: 'bar', params: { username: 'alice' } }],
|
||||
});
|
||||
|
||||
act(() => setParams({ age: 25 }, { name: 'bar' }));
|
||||
|
||||
expect(onStateChange).toBeCalledTimes(2);
|
||||
expect(onStateChange).lastCalledWith({
|
||||
index: 0,
|
||||
key: '0',
|
||||
routeNames: ['foo', 'bar'],
|
||||
routes: [
|
||||
{ key: 'foo', name: 'foo', params: undefined },
|
||||
{ key: 'bar', name: 'bar', params: { username: 'alice', age: 25 } },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('handles change in route names', () => {
|
||||
const TestNavigator = (props: any): any => {
|
||||
useNavigationBuilder(MockRouter, props);
|
||||
|
||||
@@ -4,12 +4,12 @@ import { Router } from '../types';
|
||||
import useNavigationBuilder from '../useNavigationBuilder';
|
||||
import NavigationContainer from '../NavigationContainer';
|
||||
import Screen from '../Screen';
|
||||
import MockRouter from './__fixtures__/MockRouter';
|
||||
import MockRouter, { MockActions } from './__fixtures__/MockRouter';
|
||||
|
||||
beforeEach(() => (MockRouter.key = 0));
|
||||
|
||||
it("lets parent handle the action if child didn't", () => {
|
||||
const ParentRouter: Router<{ type: string }> = {
|
||||
const ParentRouter: Router<MockActions> = {
|
||||
...MockRouter,
|
||||
|
||||
getStateForAction(state, action) {
|
||||
@@ -78,7 +78,7 @@ it("lets parent handle the action if child didn't", () => {
|
||||
});
|
||||
|
||||
it("lets children handle the action if parent didn't", () => {
|
||||
const ParentRouter: Router<{ type: string }> = {
|
||||
const ParentRouter: Router<MockActions> = {
|
||||
...MockRouter,
|
||||
|
||||
shouldActionPropagateToChildren() {
|
||||
@@ -86,7 +86,7 @@ it("lets children handle the action if parent didn't", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const ChildRouter: Router<{ type: string }> = {
|
||||
const ChildRouter: Router<MockActions> = {
|
||||
...MockRouter,
|
||||
|
||||
shouldActionChangeFocus() {
|
||||
|
||||
@@ -2,5 +2,6 @@ export { default as NavigationContainer } from './NavigationContainer';
|
||||
export { default as createNavigator } from './createNavigator';
|
||||
|
||||
export { default as useNavigationBuilder } from './useNavigationBuilder';
|
||||
export { default as BaseRouter } from './BaseRouter';
|
||||
|
||||
export * from './types';
|
||||
|
||||
@@ -135,7 +135,7 @@ export type Router<Action extends NavigationAction = CommonAction> = {
|
||||
/**
|
||||
* Action creators for the router.
|
||||
*/
|
||||
actionCreators: ActionCreators<Action>;
|
||||
actionCreators?: ActionCreators<Action>;
|
||||
};
|
||||
|
||||
export type ParamListBase = { [key: string]: object | undefined };
|
||||
@@ -149,9 +149,7 @@ class PrivateValueStore<T> {
|
||||
private __private_value_type?: T;
|
||||
}
|
||||
|
||||
export type NavigationHelpers<
|
||||
ParamList extends ParamListBase = ParamListBase
|
||||
> = {
|
||||
export type NavigationProp<ParamList extends ParamListBase = ParamListBase> = {
|
||||
/**
|
||||
* Dispatch an action or an update function to the router.
|
||||
* The update function will receive the current state,
|
||||
@@ -198,20 +196,19 @@ export type NavigationHelpers<
|
||||
* Go back to the previous route in history.
|
||||
*/
|
||||
goBack(): void;
|
||||
} & PrivateValueStore<ParamList>;
|
||||
|
||||
export type NavigationProp<
|
||||
ParamList extends ParamListBase,
|
||||
RouteName extends keyof ParamList
|
||||
> = NavigationHelpers<ParamList> & {
|
||||
/**
|
||||
* Update the param object for the route.
|
||||
* The new params will be shallow merged with the old one.
|
||||
*
|
||||
* @param params Params object for the current route.
|
||||
* @routeName params Target route for setParam.
|
||||
*/
|
||||
setParams(params: ParamList[RouteName]): void;
|
||||
};
|
||||
setParams<RouteName extends Extract<keyof ParamList, string>>(
|
||||
params: ParamList[RouteName],
|
||||
target: TargetRoute<RouteName>
|
||||
): void;
|
||||
} & PrivateValueStore<ParamList>;
|
||||
|
||||
export type RouteProp<
|
||||
ParamList extends ParamListBase,
|
||||
@@ -227,12 +224,12 @@ export type RouteProp<
|
||||
});
|
||||
|
||||
export type CompositeNavigationProp<
|
||||
A extends NavigationHelpers<ParamListBase>,
|
||||
B extends NavigationHelpers<ParamListBase>
|
||||
> = Omit<A & B, keyof NavigationHelpers<any>> &
|
||||
NavigationHelpers<
|
||||
(A extends NavigationHelpers<infer T> ? T : never) &
|
||||
(B extends NavigationHelpers<infer U> ? U : never)
|
||||
A extends NavigationProp<ParamListBase>,
|
||||
B extends NavigationProp<ParamListBase>
|
||||
> = Omit<A & B, keyof NavigationProp<any>> &
|
||||
NavigationProp<
|
||||
(A extends NavigationProp<infer T> ? T : never) &
|
||||
(B extends NavigationProp<infer U> ? U : never)
|
||||
>;
|
||||
|
||||
export type Descriptor = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
Descriptor,
|
||||
PartialState,
|
||||
NavigationAction,
|
||||
NavigationHelpers,
|
||||
NavigationProp,
|
||||
NavigationState,
|
||||
ParamListBase,
|
||||
RouteConfig,
|
||||
@@ -16,7 +16,7 @@ import NavigationBuilderContext, {
|
||||
type Options = {
|
||||
state: NavigationState | PartialState;
|
||||
screens: { [key: string]: RouteConfig<ParamListBase, string> };
|
||||
navigation: NavigationHelpers<ParamListBase>;
|
||||
navigation: NavigationProp<ParamListBase>;
|
||||
onAction: (action: NavigationAction, sourceNavigatorKey?: string) => boolean;
|
||||
getState: () => NavigationState;
|
||||
setState: (state: NavigationState) => void;
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import * as BaseActions from './BaseActions';
|
||||
import NavigationBuilderContext from './NavigationBuilderContext';
|
||||
import {
|
||||
NavigationHelpers,
|
||||
NavigationProp,
|
||||
NavigationAction,
|
||||
NavigationState,
|
||||
ActionCreators,
|
||||
@@ -13,7 +13,7 @@ type Options = {
|
||||
onAction: (action: NavigationAction, sourceNavigatorKey?: string) => boolean;
|
||||
getState: () => NavigationState;
|
||||
setState: (state: NavigationState) => void;
|
||||
actionCreators: ActionCreators;
|
||||
actionCreators?: ActionCreators;
|
||||
};
|
||||
|
||||
export default function useNavigationHelpers({
|
||||
@@ -28,7 +28,7 @@ export default function useNavigationHelpers({
|
||||
|
||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||
|
||||
return React.useMemo((): NavigationHelpers => {
|
||||
return React.useMemo((): NavigationProp => {
|
||||
const dispatch = (
|
||||
action: NavigationAction | ((state: NavigationState) => NavigationState)
|
||||
) => {
|
||||
|
||||
Reference in New Issue
Block a user