Skip to content

Commit

Permalink
refactor: move navigation.state to a route prop (facebook#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
osdnk authored and satya164 committed Jul 18, 2019
1 parent b775dba commit d3099c1
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 109 deletions.
9 changes: 3 additions & 6 deletions example/StackNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,11 @@ const StackRouter: Router<CommonAction | Action> = {
};

export function StackNavigator(props: Props) {
const { navigation, descriptors } = useNavigationBuilder(StackRouter, props);
const { state, descriptors } = useNavigationBuilder(StackRouter, props);

return (
<div style={{ position: 'relative' }}>
{navigation.state.routes.map((route, i) => (
{state.routes.map((route, i) => (
<div
key={route.key}
style={{
Expand Down Expand Up @@ -297,10 +297,7 @@ export function StackNavigator(props: Props) {
boxShadow: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)',
}}
>
{
descriptors[navigation.state.routes[navigation.state.index].key]
.options.title
}
{descriptors[state.routes[state.index].key].options.title}
</div>
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions example/TabNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,18 @@ const TabRouter: Router<Action | CommonAction> = {
};

export function TabNavigator(props: Props) {
const { navigation, descriptors } = useNavigationBuilder(TabRouter, props);
const { state, descriptors } = useNavigationBuilder(TabRouter, props);

return (
<div style={{ display: 'flex', flexDirection: 'row', height: '100%' }}>
{navigation.state.routes.map((route, i, self) => (
{state.routes.map((route, i, self) => (
<div
key={route.key}
style={{
width: `${100 / self.length}%`,
padding: 10,
borderRadius: 3,
backgroundColor: i === navigation.state.index ? 'tomato' : 'white',
backgroundColor: i === state.index ? 'tomato' : 'white',
}}
>
{descriptors[route.key].render()}
Expand Down
7 changes: 5 additions & 2 deletions example/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { render } from 'react-dom';
import {
NavigationContainer,
CompositeNavigationProp,
NavigationHelpers,
PartialState,
NavigationHelpers,
RouteProp,
} from '../src';
import Stack, { StackNavigationProp } from './StackNavigator';
import Tab, { TabNavigationProp } from './TabNavigator';
Expand All @@ -26,14 +27,16 @@ const MyTab = Tab<TabParamList>();

const First = ({
navigation,
route,
}: {
navigation: CompositeNavigationProp<
StackNavigationProp<StackParamList, 'first'>,
NavigationHelpers<TabParamList>
>;
route: RouteProp<StackParamList, 'first'>;
}) => (
<div>
<h1>First, {navigation.state.params.author}</h1>
<h1>First, {route.params.author}</h1>
<button type="button" onClick={() => navigation.push('second')}>
Push second
</button>
Expand Down
2 changes: 1 addition & 1 deletion src/NavigationBuilderContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type ChildActionListener = (
) => boolean;

const NavigationBuilderContext = React.createContext<{
helpers?: NavigationHelpers;
navigation?: NavigationHelpers;
onAction?: (action: NavigationAction, sourceNavigatorKey?: string) => boolean;
addActionListener?: (listener: ChildActionListener) => void;
removeActionListener?: (listener: ChildActionListener) => void;
Expand Down
16 changes: 8 additions & 8 deletions src/SceneView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ import {
Route,
NavigationState,
NavigationHelpers,
ScreenProps,
RouteConfig,
} from './types';
import EnsureSingleNavigator from './EnsureSingleNavigator';

type Props = {
screen: ScreenProps;
helpers: NavigationHelpers;
screen: RouteConfig;
navigation: NavigationHelpers;
route: Route & { state?: NavigationState };
getState: () => NavigationState;
setState: (state: NavigationState) => void;
};

export default function SceneView(props: Props) {
const { screen, route, helpers, getState, setState } = props;
const { screen, route, navigation: helpers, getState, setState } = props;

const navigation = React.useMemo(
() => ({
Expand All @@ -35,9 +35,8 @@ export default function SceneView(props: Props) {
),
});
},
state: route,
}),
[getState, helpers, route, setState]
[getState, helpers, route.key, setState]
);

const getCurrentState = React.useCallback(() => {
Expand Down Expand Up @@ -79,11 +78,12 @@ export default function SceneView(props: Props) {
// @ts-ignore
render={screen.component || screen.children}
navigation={navigation}
route={route}
>
{'component' in screen && screen.component !== undefined ? (
<screen.component navigation={navigation} />
<screen.component navigation={navigation} route={route} />
) : 'children' in screen && screen.children !== undefined ? (
screen.children({ navigation })
screen.children({ navigation, route })
) : null}
</StaticContainer>
</EnsureSingleNavigator>
Expand Down
4 changes: 2 additions & 2 deletions src/Screen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ScreenProps } from './types';
import { RouteConfig } from './types';

export default function Screen(_: ScreenProps) {
export default function Screen(_: RouteConfig) {
/* istanbul ignore next */
return null;
}
65 changes: 21 additions & 44 deletions src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,9 @@ beforeEach(() => (MockRouter.key = 0));

it('initializes state for a navigator on navigation', () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

const FooScreen = (props: any) => {
Expand Down Expand Up @@ -148,11 +146,9 @@ it('initializes state for a navigator on navigation', () => {

it('rehydrates state for a navigator on navigation', () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

const BarScreen = (props: any) => {
Expand Down Expand Up @@ -195,11 +191,9 @@ it('rehydrates state for a navigator on navigation', () => {

it('initializes state for nested navigator on navigation', () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

const TestScreen = (props: any) => {
Expand Down Expand Up @@ -255,11 +249,9 @@ it('initializes state for nested navigator on navigation', () => {

it("doesn't update state if nothing changed", () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

const FooScreen = (props: any) => {
Expand Down Expand Up @@ -287,11 +279,9 @@ it("doesn't update state if nothing changed", () => {

it("doesn't update state if action wasn't handled", () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

const FooScreen = (props: any) => {
Expand Down Expand Up @@ -319,11 +309,9 @@ it("doesn't update state if action wasn't handled", () => {

it('cleans up state when the navigator unmounts', () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

const FooScreen = (props: any) => {
Expand Down Expand Up @@ -383,22 +371,15 @@ it("lets parent handle the action if child didn't", () => {
};

const ParentNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(
ParentRouter,
props
);

return descriptors[
navigation.state.routes[navigation.state.index].key
].render();
const { state, descriptors } = useNavigationBuilder(ParentRouter, props);

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

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

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

const TestScreen = (props: any) => {
Expand Down Expand Up @@ -444,11 +425,9 @@ it("lets parent handle the action if child didn't", () => {

it('allows arbitrary state updates by dispatching a function', () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

const FooScreen = (props: any) => {
Expand Down Expand Up @@ -490,11 +469,9 @@ it('allows arbitrary state updates by dispatching a function', () => {

it('updates route params with setParams', () => {
const TestNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(MockRouter, props);
const { state, descriptors } = useNavigationBuilder(MockRouter, props);

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

let setParams: (params: object) => void = () => undefined;
Expand Down
16 changes: 4 additions & 12 deletions src/__tests__/useOnChildUpdate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,17 @@ it("lets children handle the action if parent didn't", () => {
};

const ChildNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(
ChildRouter,
props
);
const { state, descriptors } = useNavigationBuilder(ChildRouter, props);

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

const ParentNavigator = (props: any) => {
const { navigation, descriptors } = useNavigationBuilder(
ParentRouter,
props
);
const { state, descriptors } = useNavigationBuilder(ParentRouter, props);

return (
<React.Fragment>
{navigation.state.routes.map(route => descriptors[route.key].render())}
{state.routes.map(route => descriptors[route.key].render())}
</React.Fragment>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/createNavigator.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { ParamListBase, ScreenProps, TypedNavigator } from './types';
import { ParamListBase, RouteConfig, TypedNavigator } from './types';
import Screen from './Screen';

export default function createNavigator<N extends React.ComponentType<any>>(
Expand All @@ -12,7 +12,7 @@ export default function createNavigator<N extends React.ComponentType<any>>(
return {
Navigator: RawNavigator,
Screen: Screen as React.ComponentType<
ScreenProps<ParamList, keyof ParamList>
RouteConfig<ParamList, keyof ParamList>
>,
};
};
Expand Down
25 changes: 15 additions & 10 deletions src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,6 @@ export type NavigationProp<
ParamList extends ParamListBase,
RouteName extends keyof ParamList
> = NavigationHelpers<ParamList> & {
/**
* State for the child navigator.
*/
state: Omit<Route<RouteName>, 'params'> &
(ParamList[RouteName] extends undefined
? {}
: { params: ParamList[RouteName] });

/**
* Update the param object for the route.
* The new params will be shallow merged with the old one.
Expand All @@ -221,6 +213,19 @@ export type NavigationProp<
setParams(params: ParamList[RouteName]): void;
};

export type RouteProp<
ParamList extends ParamListBase,
RouteName extends keyof ParamList
> = Omit<Route<RouteName>, 'params'> &
(ParamList[RouteName] extends undefined
? {}
: {
/**
* Params for this route
*/
params: ParamList[RouteName];
});

export type CompositeNavigationProp<
A extends NavigationHelpers<ParamListBase>,
B extends NavigationHelpers<ParamListBase>
Expand Down Expand Up @@ -251,7 +256,7 @@ export type Options = {
[key: string]: any;
};

export type ScreenProps<
export type RouteConfig<
ParamList extends ParamListBase = ParamListBase,
RouteName extends keyof ParamList = string
> = {
Expand Down Expand Up @@ -295,5 +300,5 @@ export type TypedNavigator<
initialRouteName?: keyof ParamList;
}
>;
Screen: React.ComponentType<ScreenProps<ParamList, keyof ParamList>>;
Screen: React.ComponentType<RouteConfig<ParamList, keyof ParamList>>;
};
Loading

0 comments on commit d3099c1

Please sign in to comment.