fix: throw a descriptive error if navigation object hasn't initialized

This commit is contained in:
Satyajit Sahoo
2020-02-12 20:59:58 +01:00
parent 0cca1309ec
commit b6accd03f6
2 changed files with 59 additions and 0 deletions

View File

@@ -22,6 +22,9 @@ type State = NavigationState | PartialState<NavigationState> | undefined;
const MISSING_CONTEXT_ERROR =
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/en/getting-started.html for setup instructions.";
const NOT_INITIALIZED_ERROR =
"The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. You can ensure that all navigators have mounted after the callback to 'useEffect' is called in your root component.";
export const NavigationStateContext = React.createContext<{
isDefault?: true;
state?: NavigationState | PartialState<NavigationState>;
@@ -195,10 +198,18 @@ const BaseNavigationContainer = React.forwardRef(
const dispatch = (
action: NavigationAction | ((state: NavigationState) => NavigationAction)
) => {
if (listeners[0] == null) {
throw new Error(NOT_INITIALIZED_ERROR);
}
listeners[0](navigation => navigation.dispatch(action));
};
const canGoBack = () => {
if (listeners[0] == null) {
throw new Error(NOT_INITIALIZED_ERROR);
}
const { result, handled } = listeners[0](navigation =>
navigation.canGoBack()
);

View File

@@ -501,3 +501,51 @@ it('emits state events when the state changes', () => {
],
});
});
it('throws if there is no navigator rendered', () => {
expect.assertions(1);
const ref = React.createRef<NavigationContainerRef>();
const element = <BaseNavigationContainer ref={ref} children={null} />;
render(element);
act(() => {
expect(() => ref.current?.dispatch({ type: 'WHATEVER' })).toThrow(
"The 'navigation' object hasn't been initialized yet."
);
});
});
it("throws if the ref hasn't finished initializing", () => {
expect.assertions(1);
const ref = React.createRef<NavigationContainerRef>();
const TestNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
return descriptors[state.routes[state.index].key].render();
};
const TestScreen = () => {
React.useEffect(() => {
expect(() => ref.current?.dispatch({ type: 'WHATEVER' })).toThrow(
"The 'navigation' object hasn't been initialized yet."
);
}, []);
return null;
};
const element = (
<BaseNavigationContainer ref={ref}>
<TestNavigator>
<Screen name="foo" component={TestScreen} />
</TestNavigator>
</BaseNavigationContainer>
);
render(element);
});