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

feat: remove necessity of wrapping navigators into container #21

Closed
wants to merge 2 commits into from
Closed
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
6 changes: 2 additions & 4 deletions src/NavigationContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ const MISSING_CONTEXT_ERROR =

export const NavigationStateContext = React.createContext<{
state?: NavigationState | PartialState;
getState: () => NavigationState | PartialState | undefined;
getState: () => NavigationState | PartialState | undefined | null;
setState: (state: NavigationState | undefined) => void;
key?: string;
performTransaction: (action: () => void) => void;
}>({
get getState(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
getState: () => null,
get setState(): any {
throw new Error(MISSING_CONTEXT_ERROR);
},
Expand Down
33 changes: 20 additions & 13 deletions src/__tests__/NavigationContainer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import { render } from 'react-native-testing-library';
import NavigationContainer, {
NavigationStateContext,
} from '../NavigationContainer';
import useNavigationBuilder from "../useNavigationBuilder";
import MockRouter from "./__fixtures__/MockRouter";
import {createNavigator} from "../index";

it('throws when getState is accessed without a container', () => {
it('throws when setState is accessed without a container', () => {
expect.assertions(1);

const Test = () => {
const { getState } = React.useContext(NavigationStateContext);
const { setState } = React.useContext(NavigationStateContext);

// eslint-disable-next-line babel/no-unused-expressions
getState;
setState;

return null;
};
Expand All @@ -23,14 +26,14 @@ it('throws when getState is accessed without a container', () => {
);
});

it('throws when setState is accessed without a container', () => {
it('throws when performTransaction is accessed without a container', () => {
expect.assertions(1);

const Test = () => {
const { setState } = React.useContext(NavigationStateContext);
const { performTransaction } = React.useContext(NavigationStateContext);

// eslint-disable-next-line babel/no-unused-expressions
setState;
performTransaction;

return null;
};
Expand All @@ -42,8 +45,12 @@ it('throws when setState is accessed without a container', () => {
);
});

it('throws when performTransaction is accessed without a container', () => {
expect.assertions(1);
it('throws when performTransaction is accessed without a container but inside navigator', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't throw?

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

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

const Test = () => {
const { performTransaction } = React.useContext(NavigationStateContext);
Expand All @@ -54,11 +61,11 @@ it('throws when performTransaction is accessed without a container', () => {
return null;
};

const element = <Test />;

expect(() => render(element).update(element)).toThrowError(
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
);
const element = (
<TestNavigator.Navigator>
<TestNavigator.Screen name="name" component={Test} />
</TestNavigator.Navigator>);
render(element).update(element);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: new line before xd

});

it('throws when setState is called outside performTransaction', () => {
Expand Down
18 changes: 17 additions & 1 deletion src/createNavigator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as React from 'react';
import { ParamListBase, RouteConfig, TypedNavigator } from './types';
import Screen from './Screen';
import { NavigationStateContext } from './NavigationContainer';
import { NavigationContainer } from './index';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move the import to NavigationContainer file like above to avoid circular dep

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unrelated, but can you move the types import to bottom xd


export default function createNavigator<N extends React.ComponentType<any>>(
RawNavigator: N
Expand All @@ -10,7 +12,21 @@ export default function createNavigator<N extends React.ComponentType<any>>(
typeof RawNavigator
> {
return {
Navigator: RawNavigator,
Navigator: function Navigator(props) {
const { getState } = React.useContext(NavigationStateContext);

// @ts-ignore
const Navigator = <RawNavigator {...props} />
if (getState() === null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: new line before xd

return (
<NavigationContainer>
{Navigator}
</NavigationContainer>
);
}

return Navigator;
},
Screen: Screen as React.ComponentType<
RouteConfig<ParamList, keyof ParamList>
>,
Expand Down