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

feat: add dangerouslyGetState #63

Merged
merged 2 commits into from
Aug 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/core/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Screen from '../Screen';
import NavigationContainer from '../NavigationContainer';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
import useNavigation from '../useNavigation';
import { NavigationState } from '../types';

beforeEach(() => (MockRouterKey.current = 0));

Expand Down Expand Up @@ -467,6 +469,7 @@ it('updates route params with setParams applied to parent', () => {
{ key: 'foo', name: 'foo', params: { username: 'alice' } },
{ key: 'bar', name: 'bar' },
],
stale: false,
});

act(() => setParams({ age: 25 }));
Expand All @@ -480,6 +483,7 @@ it('updates route params with setParams applied to parent', () => {
{ key: 'foo', name: 'foo', params: { username: 'alice', age: 25 } },
{ key: 'bar', name: 'bar' },
],
stale: false,
});
});

Expand Down Expand Up @@ -519,6 +523,40 @@ it('handles change in route names', () => {
});
});

it('gives access to internal state', () => {
const TestNavigator = (props: any): any => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

return descriptors[state.routes[state.index].key].render();
};

let state: NavigationState | undefined;

const Test = () => {
const navigation = useNavigation();
state = navigation.dangerouslyGetState();
return null;
};

const root = (
<NavigationContainer>
<TestNavigator initialRouteName="bar">
<Screen name="bar" component={Test} />
</TestNavigator>
</NavigationContainer>
);

render(root).update(root);

expect(state).toEqual({
index: 0,
key: '0',
routeNames: ['bar'],
routes: [{ key: 'bar', name: 'bar' }],
stale: false,
});
});

it("throws if navigator doesn't have any screens", () => {
const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props);
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,13 @@ export type NavigationProp<
dangerouslyGetParent():
| NavigationProp<ParamListBase, string, any, any>
| undefined;

/**
* Returns the navigator's state. Reason why the function is called
* dangerouslyGetState is to discourage developers to use internal navigation's state.
* Note that this method doesn't re-render screen when the result changes. So don't use it in `render`.
*/
dangerouslyGetState(): State;
} & EventConsumer<EventMap & EventMapBase> &
PrivateValueStore<ParamList, RouteName, EventMap>;

Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/useNavigationCache.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ 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 cache = React.useMemo(
() => ({ current: {} as NavigationCache<State, ScreenOptions> }),
// eslint-disable-next-line react-hooks/exhaustive-deps
[getState, navigation, setOptions, router, emitter]
[getState, navigation, setOptions, router, emitter, parentNavigation]
);

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

const parentNavigation = React.useContext(NavigationContext);

cache.current = state.routes.reduce<NavigationCache<State, ScreenOptions>>(
(acc, route, index) => {
const previous = cache.current[route.key];
Expand Down Expand Up @@ -92,6 +92,7 @@ export default function useNavigationCache<
...helpers,
...emitter.create(route.key),
dangerouslyGetParent: () => parentNavigation,
dangerouslyGetState: getState as () => State,
dispatch,
setOptions: (options: object) =>
setOptions(o => ({
Expand Down