Rename `navigationState.children` to `navigationState.routes`.

Summary:
[Experimental API breaking changes]

The notion of `parent` or `children` in navigaton is misleading. We have no intention to maintain or
build the nested or hierarchical navigation states. To be clear, rename `navigationState.children` to
`navigationState.route`.

Reviewed By: ericvicenti

Differential Revision: D3332115

fbshipit-source-id: c72ed08acaf030fb9c60abf22fb15cc0f44b3485
This commit is contained in:
Hedger Wang 2016-05-22 16:27:53 -07:00 committed by Facebook Github Bot 2
parent 75d538e3eb
commit 1e626027f5
16 changed files with 118 additions and 111 deletions

View File

@ -50,7 +50,7 @@ const ExampleReducer = NavigationReducer.StackReducer({
initialState: {
key: 'AnimatedExampleStackKey',
index: 0,
children: [
routes: [
{key: 'First Route'},
],
},

View File

@ -43,7 +43,7 @@ const ExampleReducer = NavigationReducer.StackReducer({
initialState: {
key: 'BasicExampleStackKey',
index: 0,
children: [
routes: [
{key: 'First Route'},
],
},
@ -59,12 +59,12 @@ const NavigationBasicExample = React.createClass({
return (
<ScrollView style={styles.topView}>
<NavigationExampleRow
text={`Current page: ${this.state.children[this.state.index].key}`}
text={`Current page: ${this.state.croutes[this.state.index].key}`}
/>
<NavigationExampleRow
text={`Push page #${this.state.children.length}`}
text={`Push page #${this.state.routes.length}`}
onPress={() => {
this._handleAction({ type: 'push', key: 'page #' + this.state.children.length });
this._handleAction({ type: 'push', key: 'page #' + this.state.routes.length });
}}
/>
<NavigationExampleRow

View File

@ -57,7 +57,7 @@ function createReducer(initialState) {
const ExampleReducer = createReducer({
index: 0,
key: 'exmaple',
children: [{key: 'First Route'}],
routes: [{key: 'First Route'}],
});
class NavigationCardStackExample extends React.Component {

View File

@ -106,7 +106,7 @@ const ExampleAppReducer = NavigationReducer.TabsReducer({
initialState: {
key: 'notifs',
index: 0,
children: [
routes: [
{key: 'base', type: 'NotifsPage'},
],
},
@ -121,7 +121,7 @@ const ExampleAppReducer = NavigationReducer.TabsReducer({
initialState: {
key: 'settings',
index: 0,
children: [
routes: [
{key: 'base', type: 'SettingsPage'},
],
},
@ -136,7 +136,7 @@ const ExampleAppReducer = NavigationReducer.TabsReducer({
initialState: {
key: 'profile',
index: 0,
children: [
routes: [
{key: 'base', type: 'ProfilePage'},
],
},
@ -256,7 +256,7 @@ class NavigationCompositionExample extends React.Component {
onNavigate={this.handleAction.bind(this)}
/>
<NavigationExampleTabBar
tabs={this.state.children}
tabs={this.state.routes}
index={this.state.index}
onNavigate={this.handleAction.bind(this)}
/>
@ -284,7 +284,7 @@ class ExampleMainView extends React.Component {
_renderScene(): ReactElement {
const {navigationState} = this.props;
const childState = navigationState.children[navigationState.index];
const childState = navigationState.routes[navigationState.index];
return (
<ExampleTabScreen
key={'tab_screen' + childState.key}

View File

@ -78,13 +78,13 @@ class NavigationTabsExample extends React.Component {
return (
<View style={styles.topView}>
<ExmpleTabPage
tabs={this.state.children}
tabs={this.state.routes}
index={this.state.index}
onExampleExit={this.props.onExampleExit}
onNavigate={this.handleAction.bind(this)}
/>
<NavigationExampleTabBar
tabs={this.state.children}
tabs={this.state.routes}
index={this.state.index}
onNavigate={this.handleAction.bind(this)}
/>

View File

@ -1,4 +1,11 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
@ -39,7 +46,7 @@ export type UIExplorerNavigationState = {
const UIExplorerStackReducer = StackReducer({
getPushedReducerForAction: (action, lastState) => {
if (action.type === 'UIExplorerExampleAction' && UIExplorerList.Modules[action.openExample]) {
if (lastState.children.find(child => child.key === action.openExample)) {
if (lastState.routes.find(route => route.key === action.openExample)) {
// The example is already open, we should avoid pushing examples twice
return null;
}
@ -51,7 +58,7 @@ const UIExplorerStackReducer = StackReducer({
initialState: {
key: 'UIExplorerMainStack',
index: 0,
children: [
routes: [
{key: 'AppList'},
],
},
@ -70,7 +77,7 @@ function UIExplorerNavigationReducer(lastState: ?UIExplorerNavigationState, acti
stack: {
key: 'UIExplorerMainStack',
index: 0,
children: [
routes: [
{
key: 'AppList',
filter: action.filter,

View File

@ -44,7 +44,7 @@ const navigationRoute = PropTypes.shape({
const navigationState = PropTypes.shape({
index: PropTypes.number.isRequired,
key: PropTypes.string.isRequired,
children: PropTypes.arrayOf(navigationRoute),
routes: PropTypes.arrayOf(navigationRoute),
});
/* NavigationLayout */

View File

@ -18,34 +18,34 @@ import type {
NavigationState,
} from 'NavigationTypeDefinition';
function getParent(state: NavigationRoute): ?NavigationState {
function getParent(state: NavigationState): ?NavigationState {
if (
(state instanceof Object) &&
(state.children instanceof Array) &&
(state.children[0] !== undefined) &&
(state.routes instanceof Array) &&
(state.routes[0] !== undefined) &&
(typeof state.index === 'number') &&
(state.children[state.index] !== undefined)
(state.routes[state.index] !== undefined)
) {
return state;
}
return null;
}
function get(state: NavigationRoute, key: string): ?NavigationRoute {
function get(state: NavigationState, key: string): ?NavigationRoute {
const parentState = getParent(state);
if (!parentState) {
return null;
}
const childState = parentState.children.find(child => child.key === key);
const childState = parentState.routes.find(child => child.key === key);
return childState || null;
}
function indexOf(state: NavigationRoute, key: string): ?number {
function indexOf(state: NavigationState, key: string): ?number {
const parentState = getParent(state);
if (!parentState) {
return null;
}
const index = parentState.children.map(child => child.key).indexOf(key);
const index = parentState.routes.map(child => child.key).indexOf(key);
if (index === -1) {
return null;
}
@ -53,10 +53,10 @@ function indexOf(state: NavigationRoute, key: string): ?number {
}
function push(state: NavigationState, newChildState: NavigationRoute): NavigationState {
var lastChildren: Array<NavigationRoute> = state.children;
var lastChildren: Array<NavigationRoute> = state.routes;
return {
...state,
children: [
routes: [
...lastChildren,
newChildState,
],
@ -65,35 +65,35 @@ function push(state: NavigationState, newChildState: NavigationRoute): Navigatio
}
function pop(state: NavigationState): NavigationState {
const lastChildren = state.children;
const lastChildren = state.routes;
return {
...state,
children: lastChildren.slice(0, lastChildren.length - 1),
routes: lastChildren.slice(0, lastChildren.length - 1),
index: lastChildren.length - 2,
};
}
function reset(state: NavigationRoute, nextChildren: ?Array<NavigationRoute>, nextIndex: ?number): NavigationRoute {
function reset(state: NavigationState, nextChildren: ?Array<NavigationRoute>, nextIndex: ?number): NavigationState {
const parentState = getParent(state);
if (!parentState) {
return state;
}
const children = nextChildren || parentState.children;
const routes = nextChildren || parentState.routes;
const index = nextIndex == null ? parentState.index : nextIndex;
if (children === parentState.children && index === parentState.index) {
if (routes === parentState.routes && index === parentState.index) {
return state;
}
return {
...parentState,
children,
routes,
index,
};
}
function set(state: ?NavigationRoute, key: string, nextChildren: Array<NavigationRoute>, nextIndex: number): NavigationRoute {
function set(state: ?NavigationState, key: string, nextChildren: Array<NavigationRoute>, nextIndex: number): NavigationState {
if (!state) {
return {
children: nextChildren,
routes: nextChildren,
index: nextIndex,
key,
};
@ -101,23 +101,23 @@ function set(state: ?NavigationRoute, key: string, nextChildren: Array<Navigatio
const parentState = getParent(state);
if (!parentState) {
return {
children: nextChildren,
routes: nextChildren,
index: nextIndex,
key,
};
}
if (nextChildren === parentState.children && nextIndex === parentState.index && key === parentState.key) {
if (nextChildren === parentState.routes && nextIndex === parentState.index && key === parentState.key) {
return parentState;
}
return {
...parentState,
children: nextChildren,
routes: nextChildren,
index: nextIndex,
key,
};
}
function jumpToIndex(state: NavigationRoute, index: number): NavigationRoute {
function jumpToIndex(state: NavigationState, index: number): NavigationState {
const parentState = getParent(state);
if (parentState && parentState.index === index) {
return parentState;
@ -128,12 +128,12 @@ function jumpToIndex(state: NavigationRoute, index: number): NavigationRoute {
};
}
function jumpTo(state: NavigationRoute, key: string): NavigationRoute {
function jumpTo(state: NavigationState, key: string): NavigationState {
const parentState = getParent(state);
if (!parentState) {
return state;
}
const index = parentState.children.indexOf(parentState.children.find(child => child.key === key));
const index = parentState.routes.indexOf(parentState.routes.find(child => child.key === key));
invariant(
index !== -1,
'Cannot find child with matching key in this NavigationRoute'
@ -144,34 +144,34 @@ function jumpTo(state: NavigationRoute, key: string): NavigationRoute {
};
}
function replaceAt(state: NavigationRoute, key: string, newState: NavigationRoute): NavigationRoute {
function replaceAt(state: NavigationState, key: string, newState: NavigationState): NavigationState {
const parentState = getParent(state);
if (!parentState) {
return state;
}
const children = [...parentState.children];
const index = parentState.children.indexOf(parentState.children.find(child => child.key === key));
const routes = [...parentState.routes];
const index = parentState.routes.indexOf(parentState.routes.find(child => child.key === key));
invariant(
index !== -1,
'Cannot find child with matching key in this NavigationRoute'
);
children[index] = newState;
routes[index] = newState;
return {
...parentState,
children,
routes,
};
}
function replaceAtIndex(state: NavigationRoute, index: number, newState: NavigationRoute): NavigationRoute {
function replaceAtIndex(state: NavigationState, index: number, newState: NavigationState): NavigationState {
const parentState = getParent(state);
if (!parentState) {
return state;
}
const children = [...parentState.children];
children[index] = newState;
const routes = [...parentState.routes];
routes[index] = newState;
return {
...parentState,
children,
routes,
};
}

View File

@ -28,7 +28,7 @@ export type NavigationRoute = {
export type NavigationState = {
key: string,
index: number,
children: Array<NavigationRoute>,
routes: Array<NavigationRoute>,
};
export type NavigationAction = any;

View File

@ -91,7 +91,7 @@ function NavigationScenesReducer(
});
const nextKeys = new Set();
nextState.children.forEach((route, index) => {
nextState.routes.forEach((route, index) => {
const key = SCENE_KEY_PREFIX + route.key;
const scene = {
index,
@ -101,8 +101,8 @@ function NavigationScenesReducer(
};
invariant(
!nextKeys.has(key),
`navigationState.children[${index}].key "${key}" conflicts with` +
'another child!'
`navigationState.routes[${index}].key "${key}" conflicts with` +
'another route!'
);
nextKeys.add(key);
@ -115,8 +115,8 @@ function NavigationScenesReducer(
});
if (prevState) {
// Look at the previous children and classify any removed scenes as `stale`.
prevState.children.forEach((route: NavigationRoute, index) => {
// Look at the previous routes and classify any removed scenes as `stale`.
prevState.routes.forEach((route: NavigationRoute, index) => {
const key = SCENE_KEY_PREFIX + route.key;
if (freshScenes.has(key)) {
return;

View File

@ -7,7 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule NavigationStackReducer
* @flow
* @flow-broken
*/
'use strict';
@ -29,7 +29,7 @@ export type StackReducerConfig = {
* Must be a NavigationState:
*
* {
* children: [
* routes: [
* {key: 'subState0'},
* {key: 'subState1'},
* ],
@ -66,15 +66,15 @@ function NavigationStackReducer({initialState, getReducerForState, getPushedRedu
return lastState;
}
const activeSubState = lastParentState.children[lastParentState.index];
const activeSubState = lastParentState.routes[lastParentState.index];
const activeSubReducer = getReducerForStateWithDefault(activeSubState);
const nextActiveState = activeSubReducer(activeSubState, action);
if (nextActiveState !== activeSubState) {
const nextChildren = [...lastParentState.children];
const nextChildren = [...lastParentState.routes];
nextChildren[lastParentState.index] = nextActiveState;
return {
...lastParentState,
children: nextChildren,
routes: nextChildren,
};
}
@ -89,7 +89,7 @@ function NavigationStackReducer({initialState, getReducerForState, getPushedRedu
switch (action.type) {
case 'back':
case 'BackAction':
if (lastParentState.index === 0 || lastParentState.children.length === 1) {
if (lastParentState.index === 0 || lastParentState.routes.length === 1) {
return lastParentState;
}
return NavigationStateUtils.pop(lastParentState);

View File

@ -7,7 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule NavigationTabsReducer
* @flow
* @flow-broken
*/
'use strict';
@ -44,7 +44,7 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
return function(lastNavState: ?NavigationRoute, action: ?any): NavigationRoute {
if (!lastNavState) {
lastNavState = {
children: tabReducers.map(reducer => reducer(null, null)),
routes: tabReducers.map(reducer => reducer(null, null)),
index: initialIndex || 0,
key,
};
@ -68,10 +68,10 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
return lastParentNavState;
}
const parentState = NavigationStateUtils.getParent(navState);
const tabState = parentState && parentState.children[tabIndex];
const tabState = parentState && parentState.routes[tabIndex];
const nextTabState = tabReducer(tabState, tabAction);
if (nextTabState && tabState !== nextTabState) {
const tabs = parentState && parentState.children || [];
const tabs = parentState && parentState.routes || [];
tabs[tabIndex] = nextTabState;
return {
...lastParentNavState,

View File

@ -19,7 +19,7 @@ const NavigationScenesReducer = require('NavigationScenesReducer');
function testTransition(states) {
const routes = states.map(keys => {
return {
children: keys.map(key => {
routes: keys.map(key => {
return { key };
}),
};

View File

@ -23,7 +23,7 @@ describe('NavigationStackReducer', () => {
it('provides default/initial state', () => {
const initialState = {
children: [
routes: [
{key: 'a'},
],
index: 0,
@ -48,7 +48,7 @@ describe('NavigationStackReducer', () => {
},
getReducerForState: (state) => () => state,
initialState: {
children: [
routes: [
{key: 'first'},
],
index: 0,
@ -56,15 +56,15 @@ describe('NavigationStackReducer', () => {
}
});
const state1 = reducer(null, {type: 'default'});
expect(state1.children.length).toBe(1);
expect(state1.children[0].key).toBe('first');
expect(state1.routes.length).toBe(1);
expect(state1.routes[0].key).toBe('first');
expect(state1.index).toBe(0);
const action = {type: 'TestPushAction', testValue: 'second'};
const state2 = reducer(state1, action);
expect(state2.children.length).toBe(2);
expect(state2.children[0].key).toBe('first');
expect(state2.children[1].key).toBe('second');
expect(state2.routes.length).toBe(2);
expect(state2.routes[0].key).toBe('first');
expect(state2.routes[1].key).toBe('second');
expect(state2.index).toBe(1);
});
@ -78,7 +78,7 @@ describe('NavigationStackReducer', () => {
},
getReducerForState: (state) => () => state,
initialState: {
children: [
routes: [
{key: 'a'},
{key: 'b'},
],
@ -88,15 +88,15 @@ describe('NavigationStackReducer', () => {
});
const state1 = reducer(null, {type: 'MyDefaultAction'});
expect(state1.children[0].key).toBe('a');
expect(state1.children[1].key).toBe('b');
expect(state1.children.length).toBe(2);
expect(state1.routes[0].key).toBe('a');
expect(state1.routes[1].key).toBe('b');
expect(state1.routes.length).toBe(2);
expect(state1.index).toBe(1);
expect(state1.key).toBe('myStack');
const state2 = reducer(state1, NavigationRootContainer.getBackAction());
expect(state2.children[0].key).toBe('a');
expect(state2.children.length).toBe(1);
expect(state2.routes[0].key).toBe('a');
expect(state2.routes.length).toBe(1);
expect(state2.index).toBe(0);
const state3 = reducer(state2, NavigationRootContainer.getBackAction());
@ -107,7 +107,7 @@ describe('NavigationStackReducer', () => {
const subReducer = NavigationStackReducer({
getPushedReducerForAction: () => {},
initialState: {
children: [
routes: [
{key: 'first'},
{key: 'second'},
],
@ -131,7 +131,7 @@ describe('NavigationStackReducer', () => {
return () => state;
},
initialState: {
children: [
routes: [
{key: 'a'},
],
index: 0,
@ -141,18 +141,18 @@ describe('NavigationStackReducer', () => {
const state1 = reducer(null, {type: 'MyDefaultAction'});
const state2 = reducer(state1, {type: 'TestPushAction'});
expect(state2.children.length).toBe(2);
expect(state2.children[0].key).toBe('a');
expect(state2.children[1].key).toBe('myInnerStack');
expect(state2.children[1].children.length).toBe(2);
expect(state2.children[1].children[0].key).toBe('first');
expect(state2.children[1].children[1].key).toBe('second');
expect(state2.routes.length).toBe(2);
expect(state2.routes[0].key).toBe('a');
expect(state2.routes[1].key).toBe('myInnerStack');
expect(state2.routes[1].routes.length).toBe(2);
expect(state2.routes[1].routes[0].key).toBe('first');
expect(state2.routes[1].routes[1].key).toBe('second');
const state3 = reducer(state2, NavigationRootContainer.getBackAction());
expect(state3.children.length).toBe(2);
expect(state3.children[0].key).toBe('a');
expect(state3.children[1].key).toBe('myInnerStack');
expect(state3.children[1].children.length).toBe(1);
expect(state3.children[1].children[0].key).toBe('first');
expect(state3.routes.length).toBe(2);
expect(state3.routes[0].key).toBe('a');
expect(state3.routes[1].key).toBe('myInnerStack');
expect(state3.routes[1].routes.length).toBe(1);
expect(state3.routes[1].routes[0].key).toBe('first');
});
});

View File

@ -35,10 +35,10 @@ describe('NavigationTabsReducer', () => {
let navState = reducer();
expect(navState.children[0]).toBe('a');
expect(navState.children[1]).toBe('b');
expect(navState.children[2]).toBe('c');
expect(navState.children.length).toBe(3);
expect(navState.routes[0]).toBe('a');
expect(navState.routes[1]).toBe('b');
expect(navState.routes[2]).toBe('c');
expect(navState.routes.length).toBe(3);
expect(navState.index).toBe(1);
navState = reducer(
@ -46,10 +46,10 @@ describe('NavigationTabsReducer', () => {
JumpToAction(2)
);
expect(navState.children[0]).toEqual('a');
expect(navState.children[1]).toEqual('b');
expect(navState.children[2]).toEqual('c');
expect(navState.children.length).toBe(3);
expect(navState.routes[0]).toEqual('a');
expect(navState.routes[1]).toEqual('b');
expect(navState.routes[2]).toEqual('c');
expect(navState.routes.length).toBe(3);
expect(navState.index).toBe(2);
});

View File

@ -16,18 +16,18 @@ jest
var NavigationStateUtils = require('NavigationStateUtils');
var VALID_PARENT_STATES = [
{children: ['a','b'], index: 0},
{children: [{key: 'a'},{key: 'b', foo: 123}], index: 1},
{children: [{key: 'a'},{key: 'b'}], index: 0},
{children: [{key: 'a'},{key: 'b'}], index: 2},
{routes: ['a','b'], index: 0},
{routes: [{key: 'a'},{key: 'b', foo: 123}], index: 1},
{routes: [{key: 'a'},{key: 'b'}], index: 0},
{routes: [{key: 'a'},{key: 'b'}], index: 2},
];
var INVALID_PARENT_STATES = [
'foo',
{},
{children: [{key: 'a'}], index: 4},
{children: [{key: 'a'}], index: -1},
{children: [{key: 'a'}]},
{children: {key: 'foo'}},
{routes: [{key: 'a'}], index: 4},
{routes: [{key: 'a'}], index: -1},
{routes: [{key: 'a'}]},
{routes: {key: 'foo'}},
12,
null,
undefined,
@ -47,9 +47,9 @@ describe('NavigationStateUtils', () => {
}
});
it('can get children', () => {
it('can get routes', () => {
var fooState = {key: 'foo'};
var navState = {children: [{key: 'foobar'}, fooState], index: 0};
var navState = {routes: [{key: 'foobar'}, fooState], index: 0};
expect(NavigationStateUtils.get(navState, 'foo')).toBe(fooState);
expect(NavigationStateUtils.get(navState, 'missing')).toBe(null);
});