diff --git a/README.md b/README.md index 47d05fc6..eb73cb6d 100644 --- a/README.md +++ b/README.md @@ -306,12 +306,10 @@ For example, the path `/rooms/chat?user=jane` will be translated to a state obje ```js { - stale: true, routes: [ { name: 'rooms', state: { - stale: true, routes: [ { name: 'chat', diff --git a/packages/core/src/__tests__/BaseRouter.test.tsx b/packages/core/src/__tests__/BaseRouter.test.tsx index f90dffe7..930891df 100644 --- a/packages/core/src/__tests__/BaseRouter.test.tsx +++ b/packages/core/src/__tests__/BaseRouter.test.tsx @@ -4,6 +4,7 @@ import * as BaseActions from '../BaseActions'; jest.mock('shortid', () => () => 'test'); const STATE = { + stale: false as false, key: 'root', index: 1, routes: [ @@ -21,6 +22,7 @@ it('replaces focused screen with REPLACE', () => { ); expect(result).toEqual({ + stale: false, key: 'root', index: 1, routes: [ @@ -39,6 +41,7 @@ it('replaces source screen with REPLACE', () => { }); expect(result).toEqual({ + stale: false, key: 'root', index: 1, routes: [ @@ -66,6 +69,7 @@ it('sets params for the focused screen with SET_PARAMS', () => { ); expect(result).toEqual({ + stale: false, key: 'root', index: 1, routes: [ @@ -84,6 +88,7 @@ it('sets params for the source screen with SET_PARAMS', () => { }); expect(result).toEqual({ + stale: false, key: 'root', index: 1, routes: [ diff --git a/packages/core/src/__tests__/NavigationContainer.test.tsx b/packages/core/src/__tests__/NavigationContainer.test.tsx index 49e10fe2..566fca46 100644 --- a/packages/core/src/__tests__/NavigationContainer.test.tsx +++ b/packages/core/src/__tests__/NavigationContainer.test.tsx @@ -296,7 +296,6 @@ it('handle resetting state with ref', () => { render(element).update(element); const state = { - stale: true, index: 1, routes: [ { diff --git a/packages/core/src/__tests__/__fixtures__/MockRouter.tsx b/packages/core/src/__tests__/__fixtures__/MockRouter.tsx index dbf13e1d..e430ebf1 100644 --- a/packages/core/src/__tests__/__fixtures__/MockRouter.tsx +++ b/packages/core/src/__tests__/__fixtures__/MockRouter.tsx @@ -20,6 +20,7 @@ export default function MockRouter(options: DefaultRouterOptions) { : routeNames.indexOf(options.initialRouteName); return { + stale: false, key: String(MockRouterKey.current++), index, routeNames, @@ -34,7 +35,7 @@ export default function MockRouter(options: DefaultRouterOptions) { getRehydratedState(partialState, { routeNames, routeParamList }) { let state = partialState; - if (!state.stale) { + if (state.stale === false) { return state as NavigationState; } diff --git a/packages/core/src/__tests__/getStateFromPath.test.tsx b/packages/core/src/__tests__/getStateFromPath.test.tsx index dde0695f..c0361719 100644 --- a/packages/core/src/__tests__/getStateFromPath.test.tsx +++ b/packages/core/src/__tests__/getStateFromPath.test.tsx @@ -6,17 +6,14 @@ it('converts path string to initial state', () => { 'foo/bar/baz%20qux?author=%22jane%20%26%20co%22&valid=true' ) ).toEqual({ - stale: true, routes: [ { name: 'foo', state: { - stale: true, routes: [ { name: 'bar', state: { - stale: true, routes: [ { name: 'baz qux', @@ -34,12 +31,10 @@ it('converts path string to initial state', () => { it('handles leading slash when converting', () => { expect(getStateFromPath('/foo/bar/?count=42')).toEqual({ - stale: true, routes: [ { name: 'foo', state: { - stale: true, routes: [ { name: 'bar', @@ -54,12 +49,10 @@ it('handles leading slash when converting', () => { it('handles ending slash when converting', () => { expect(getStateFromPath('foo/bar/?count=42')).toEqual({ - stale: true, routes: [ { name: 'foo', state: { - stale: true, routes: [ { name: 'bar', @@ -74,12 +67,10 @@ it('handles ending slash when converting', () => { it('handles route without param', () => { expect(getStateFromPath('foo/bar')).toEqual({ - stale: true, routes: [ { name: 'foo', state: { - stale: true, routes: [{ name: 'bar' }], }, }, diff --git a/packages/core/src/__tests__/index.test.tsx b/packages/core/src/__tests__/index.test.tsx index 61a6afff..1a5b6039 100644 --- a/packages/core/src/__tests__/index.test.tsx +++ b/packages/core/src/__tests__/index.test.tsx @@ -49,6 +49,7 @@ it('initializes state for a navigator on navigation', () => { expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).toBeCalledWith({ + stale: false, index: 0, key: '0', routeNames: ['foo', 'bar', 'baz'], @@ -140,6 +141,7 @@ it('initializes state for nested screens in React.Fragment', () => { expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).toBeCalledWith({ + stale: false, index: 0, key: '0', routeNames: ['foo', 'bar', 'baz'], @@ -189,6 +191,7 @@ it('initializes state for nested navigator on navigation', () => { expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).toBeCalledWith({ + stale: false, index: 2, key: '0', routeNames: ['foo', 'bar', 'baz'], @@ -199,6 +202,7 @@ it('initializes state for nested navigator on navigation', () => { key: 'baz', name: 'baz', state: { + stale: false, index: 0, key: '1', routeNames: ['qux'], @@ -302,6 +306,7 @@ it('cleans up state when the navigator unmounts', () => { expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).lastCalledWith({ + stale: false, index: 0, key: '0', routeNames: ['foo', 'bar'], @@ -353,6 +358,7 @@ it('allows arbitrary state updates by dispatching a function', () => { expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).toBeCalledWith({ + stale: false, index: 1, key: '0', routeNames: ['foo', 'bar'], @@ -390,6 +396,7 @@ it('updates route params with setParams', () => { expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).lastCalledWith({ + stale: false, index: 0, key: '0', routeNames: ['foo', 'bar'], @@ -403,6 +410,7 @@ it('updates route params with setParams', () => { expect(onStateChange).toBeCalledTimes(2); expect(onStateChange).lastCalledWith({ + stale: false, index: 0, key: '0', routeNames: ['foo', 'bar'], @@ -441,6 +449,7 @@ it('handles change in route names', () => { ); expect(onStateChange).toBeCalledWith({ + stale: false, index: 0, key: '0', routeNames: ['foo', 'baz', 'qux'], diff --git a/packages/core/src/__tests__/useOnAction.test.tsx b/packages/core/src/__tests__/useOnAction.test.tsx index 257af0d3..22e873fd 100644 --- a/packages/core/src/__tests__/useOnAction.test.tsx +++ b/packages/core/src/__tests__/useOnAction.test.tsx @@ -75,6 +75,7 @@ it("lets parent handle the action if child didn't", () => { expect(onStateChange).toBeCalledTimes(1); expect(onStateChange).lastCalledWith({ + stale: false, index: 2, key: '0', routeNames: ['foo', 'bar', 'baz'], diff --git a/packages/core/src/getStateFromPath.tsx b/packages/core/src/getStateFromPath.tsx index da482249..85659a81 100644 --- a/packages/core/src/getStateFromPath.tsx +++ b/packages/core/src/getStateFromPath.tsx @@ -18,7 +18,6 @@ export default function getStateFromPath( while (segments.length) { const state = { - stale: true, routes: [{ name: decodeURIComponent(segments[0]) }], }; diff --git a/packages/core/src/types.tsx b/packages/core/src/types.tsx index 3a0fa020..acb349f0 100644 --- a/packages/core/src/types.tsx +++ b/packages/core/src/types.tsx @@ -24,20 +24,19 @@ export type NavigationState = { /** * Whether the navigation state has been rehydrated. */ - stale?: false; + stale: false; }; export type InitialState = Partial< Omit > & { - stale?: boolean; routes: Array, 'key'> & { state?: InitialState }>; }; export type PartialState = Partial< Omit > & { - stale?: boolean; + stale?: true; routes: Array< Omit, 'key'> & { key?: string; state?: InitialState } >; @@ -128,7 +127,7 @@ export type Router< * @param options.routeParamsList Object containing params for each route. */ getRehydratedState( - partialState: PartialState, + partialState: PartialState | State, options: { routeNames: string[]; routeParamList: ParamListBase; diff --git a/packages/core/src/useNavigationBuilder.tsx b/packages/core/src/useNavigationBuilder.tsx index c1a37ed9..7b2e1058 100644 --- a/packages/core/src/useNavigationBuilder.tsx +++ b/packages/core/src/useNavigationBuilder.tsx @@ -162,7 +162,7 @@ export default function useNavigationBuilder< // If the state isn't initialized, or stale, use the state we initialized instead // The state won't update until there's a change needed in the state we have initalized locally // So it'll be `undefined` or stale untill the first navigation event happens - currentState === undefined || currentState.stale + currentState === undefined || currentState.stale !== false ? (initializedStateRef.current as State) : (currentState as State); @@ -201,7 +201,7 @@ export default function useNavigationBuilder< const getState = React.useCallback((): State => { const currentState = getCurrentState(); - return currentState === undefined || currentState.stale + return currentState === undefined || currentState.stale !== false ? (initializedStateRef.current as State) : (currentState as State); }, [getCurrentState]); diff --git a/packages/example/src/index.tsx b/packages/example/src/index.tsx index 3dc56448..afbe579b 100644 --- a/packages/example/src/index.tsx +++ b/packages/example/src/index.tsx @@ -72,13 +72,11 @@ export default function App() { const state = getStateFromPath(path); return { - stale: true, routes: [ { name: 'root', state: { ...state, - stale: true, routes: [{ name: 'home' }, ...(state ? state.routes : [])], }, }, diff --git a/packages/routers/src/DrawerRouter.tsx b/packages/routers/src/DrawerRouter.tsx index 62d10077..83c3cea1 100644 --- a/packages/routers/src/DrawerRouter.tsx +++ b/packages/routers/src/DrawerRouter.tsx @@ -55,6 +55,7 @@ export default function DrawerRouter( : routeNames.indexOf(options.initialRouteName); return { + stale: false, key: `drawer-${shortid()}`, index, routeNames, @@ -69,8 +70,8 @@ export default function DrawerRouter( }, getRehydratedState(partialState, { routeNames, routeParamList }) { - if (!partialState.stale) { - return partialState as DrawerNavigationState; + if (partialState.stale === false) { + return partialState; } const state = router.getRehydratedState(partialState, { diff --git a/packages/routers/src/StackRouter.tsx b/packages/routers/src/StackRouter.tsx index 4b09fc42..66ec24ce 100644 --- a/packages/routers/src/StackRouter.tsx +++ b/packages/routers/src/StackRouter.tsx @@ -54,6 +54,7 @@ export default function StackRouter(options: StackRouterOptions) { : routeNames[0]; return { + stale: false, key: `stack-${shortid()}`, index: 0, routeNames, @@ -70,8 +71,8 @@ export default function StackRouter(options: StackRouterOptions) { getRehydratedState(partialState, { routeNames, routeParamList }) { let state = partialState; - if (!state.stale) { - return state as StackNavigationState; + if (state.stale === false) { + return state; } const routes = state.routes diff --git a/packages/routers/src/TabRouter.tsx b/packages/routers/src/TabRouter.tsx index cb5f800d..cceb1112 100644 --- a/packages/routers/src/TabRouter.tsx +++ b/packages/routers/src/TabRouter.tsx @@ -2,6 +2,7 @@ import shortid from 'shortid'; import { CommonAction, BaseRouter, + PartialState, NavigationState, DefaultRouterOptions, Router, @@ -60,6 +61,7 @@ export default function TabRouter({ : routeNames.indexOf(initialRouteName); return { + stale: false, key: `tab-${shortid()}`, index, routeNames, @@ -75,12 +77,14 @@ export default function TabRouter({ getRehydratedState(partialState, { routeNames, routeParamList }) { let state = partialState; - if (!state.stale) { - return state as TabNavigationState; + if (state.stale === false) { + return state; } const routes = routeNames.map(name => { - const route = state.routes.find(r => r.name === name); + const route = (state as PartialState).routes.find( + r => r.name === name + ); return { ...route,