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

Commit

Permalink
feat: add useRoute (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
osdnk authored Aug 31, 2019
1 parent 4e0ebb0 commit b0a3756
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 9 deletions.
19 changes: 15 additions & 4 deletions packages/core/src/NavigationContext.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import * as React from 'react';
import { NavigationProp, ParamListBase } from './types';
import {
NavigationProp,
ParamListBase,
PartialState,
Route,
NavigationState,
} from './types';

/**
* Context which holds the navigation prop for a screen.
*/
const NavigationContext = React.createContext<
NavigationProp<ParamListBase, string, any, any> | undefined
>(undefined);
const NavigationContext = React.createContext<{
navigation: NavigationProp<ParamListBase, string, any, any> | undefined;
route:
| Route<string> & {
state?: NavigationState | PartialState<NavigationState>;
}
| undefined;
}>({ navigation: undefined, route: undefined });

export default NavigationContext;
10 changes: 9 additions & 1 deletion packages/core/src/SceneView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,16 @@ export default function SceneView<
]
);

const navigationContext = React.useMemo(
() => ({
navigation,
route,
}),
[navigation, route]
);

return (
<NavigationContext.Provider value={navigation}>
<NavigationContext.Provider value={navigationContext}>
<NavigationStateContext.Provider value={context}>
<EnsureSingleNavigator>
<StaticContainer
Expand Down
34 changes: 34 additions & 0 deletions packages/core/src/__tests__/useRoute.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as React from 'react';
import { render } from 'react-native-testing-library';
import useNavigationBuilder from '../useNavigationBuilder';
import useRoute from '../useRoute';
import NavigationContainer from '../NavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
import { RouteProp } from '../types';

it('gets route prop from context', () => {
expect.assertions(1);

const TestNavigator = (props: any): any => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

return state.routes.map(route => descriptors[route.key].render());
};

const Test = () => {
const route = useRoute<RouteProp<{ sample: { x: string } }, 'sample'>>();

expect(route && route.params && route.params.x).toEqual(1);

return null;
};

render(
<NavigationContainer>
<TestNavigator>
<Screen name="foo" component={Test} initialParams={{ x: 1 }} />
</TestNavigator>
</NavigationContainer>
);
});
1 change: 1 addition & 0 deletions packages/core/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { default as NavigationContext } from './NavigationContext';

export { default as useNavigationBuilder } from './useNavigationBuilder';
export { default as useNavigation } from './useNavigation';
export { default as useRoute } from './useRoute';
export { default as useFocusEffect } from './useFocusEffect';
export { default as useIsFocused } from './useIsFocused';

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/useFocusEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type Options = {
* Hook to take care of emitting `focus` and `blur` events.
*/
export default function useFocusEvents({ state, emitter }: Options) {
const navigation = React.useContext(NavigationContext);
const { navigation } = React.useContext(NavigationContext);
const lastFocusedKeyRef = React.useRef<string | undefined>();

const currentFocusedKey = state.routes[state.index].key;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/useNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { NavigationProp, ParamListBase } from './types';
export default function useNavigation<
T extends NavigationProp<ParamListBase>
>(): T {
const navigation = React.useContext(NavigationContext);
const { navigation } = React.useContext(NavigationContext);

if (navigation === undefined) {
throw new Error(
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/useNavigationCache.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default function useNavigationCache<
// 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 parentNavigation = React.useContext(NavigationContext);
const { navigation: parentNavigation } = React.useContext(NavigationContext);

const cache = React.useMemo(
() => ({ current: {} as NavigationCache<State, ScreenOptions> }),
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/useNavigationHelpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export default function useNavigationHelpers<
Action extends NavigationAction,
EventMap extends { [key: string]: any }
>({ onAction, getState, setState, emitter, router }: Options<State, Action>) {
const parentNavigationHelpers = React.useContext(NavigationContext);
const { navigation: parentNavigationHelpers } = React.useContext(
NavigationContext
);
const { performTransaction } = React.useContext(NavigationStateContext);

return React.useMemo(() => {
Expand Down
22 changes: 22 additions & 0 deletions packages/core/src/useRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';
import NavigationContext from './NavigationContext';
import { ParamListBase, RouteProp } from './types';

/**
* Hook to access the route prop of the parent screen anywhere.
*
* @returns Route prop of the parent screen.
*/
export default function useRoute<
T extends RouteProp<ParamListBase, string>
>(): T {
const { route } = React.useContext(NavigationContext);

if (route === undefined) {
throw new Error(
"We couldn't find a route object. Is your component inside a navigator?"
);
}

return route as T;
}

0 comments on commit b0a3756

Please sign in to comment.