Skip to content

Commit

Permalink
normalize action name with prefix and expose it from module
Browse files Browse the repository at this point in the history
This is a follow up of aksonov#843 which has been reverted (aksonov#899) since it breaks
existig apps as aksonov#894 described.

change description:

  * all actions now defined in a separate file: `ActionConst.js`.
  * create an mapping object called: `ActionMap` in `Actions.js`,
    it maps deprecated string literal actions to constant one.

router:

  * will dispatch constant actions if we have dispatch method in props
  * will pass unmodified type into onNavigate.

reducer:

  * always use ActionConst and ActionMap to determine whether an action type matched or not

know issue:

  it's really hard to not break ANY existing app.
  especially for those who:
    1. stores routing status outside from RNRF
    2. use custom reducer instead of RNRF default reducer
  should be always use action constant from RNRF.

it will NOT break if user uses RNRF default reducer.
  • Loading branch information
zxcpoiu committed Jul 8, 2016
1 parent 3a1c8fa commit e047499
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 75 deletions.
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Actions from './src/Actions';
import * as ActionConst from './src/ActionConst';
import DefaultRenderer from './src/DefaultRenderer';
import Modal from './src/Modal';
import NavBar from './src/NavBar';
Expand All @@ -12,6 +13,7 @@ import Util from './src/Util';

export {
Actions,
ActionConst,
DefaultRenderer,
Modal,
NavBar,
Expand Down
9 changes: 9 additions & 0 deletions src/ActionConst.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const JUMP = 'REACT_NATIVE_ROUTER_FLUX_JUMP';
export const PUSH = 'REACT_NATIVE_ROUTER_FLUX_PUSH';
export const REPLACE = 'REACT_NATIVE_ROUTER_FLUX_REPLACE';
export const BACK = 'REACT_NATIVE_ROUTER_FLUX_BACK';
export const BACK_ACTION = 'REACT_NATIVE_ROUTER_FLUX_BACK_ACTION';
export const POP_TO = 'REACT_NATIVE_ROUTER_FLUX_POP_TO';
export const REFRESH = 'REACT_NATIVE_ROUTER_FLUX_REFRESH';
export const RESET = 'REACT_NATIVE_ROUTER_FLUX_RESET';
export const FOCUS = 'REACT_NATIVE_ROUTER_FLUX_FOCUS';
63 changes: 34 additions & 29 deletions src/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,28 @@
*/
import { assert } from './Util';
import Scene from './Scene';
export const JUMP_ACTION = 'REACT_NATIVE_ROUTER_FLUX_JUMP';
export const PUSH_ACTION = 'REACT_NATIVE_ROUTER_FLUX_PUSH';
export const REPLACE_ACTION = 'REACT_NATIVE_ROUTER_FLUX_REPLACE';
export const POP_ACTION2 = 'REACT_NATIVE_ROUTER_FLUX_BACK';
export const POP_ACTION = 'REACT_NATIVE_ROUTER_FLUX_BACK_ACTION';
export const POP_TO = 'REACT_NATIVE_ROUTER_FLUX_POP_TO';
export const REFRESH_ACTION = 'REACT_NATIVE_ROUTER_FLUX_REFRESH';
export const RESET_ACTION = 'REACT_NATIVE_ROUTER_FLUX_RESET';
export const FOCUS_ACTION = 'REACT_NATIVE_ROUTER_FLUX_FOCUS';
import * as ActionConst from './ActionConst';

export const ActionMap = {
jump: ActionConst.JUMP,
push: ActionConst.PUSH,
replace: ActionConst.REPLACE,
back: ActionConst.BACK,
BackAction: ActionConst.BACK_ACTION,
popTo: ActionConst.POP_TO,
refresh: ActionConst.REFRESH,
reset: ActionConst.RESET,
focus: ActionConst.FOCUS,
[ActionConst.JUMP]: ActionConst.JUMP,
[ActionConst.PUSH]: ActionConst.PUSH,
[ActionConst.REPLACE]: ActionConst.REPLACE,
[ActionConst.BACK]: ActionConst.BACK,
[ActionConst.BACK_ACTION]: ActionConst.BACK_ACTION,
[ActionConst.POP_TO]: ActionConst.POP_TO,
[ActionConst.REFRESH]: ActionConst.REFRESH,
[ActionConst.RESET]: ActionConst.RESET,
[ActionConst.FOCUS]: ActionConst.FOCUS,
};

function filterParam(data) {
if (data.toString() !== '[object Object]') {
Expand All @@ -31,19 +44,11 @@ function filterParam(data) {
}

const reservedKeys = [
POP_ACTION,
POP_ACTION2,
POP_TO,
REFRESH_ACTION,
REPLACE_ACTION,
JUMP_ACTION,
PUSH_ACTION,
FOCUS_ACTION,
RESET_ACTION,
'create',
'callback',
'iterate',
'current',
...Object.keys(ActionMap),
];

function getInheritProps(props) {
Expand Down Expand Up @@ -72,9 +77,9 @@ class Actions {
`'${key}' is not allowed as key name. Reserved keys: [${reservedKeys.join(', ')}]`
);
const { children, component, ...staticProps } = root.props;
let type = root.props.type || (parentProps.tabs ? JUMP_ACTION : PUSH_ACTION);
let type = root.props.type || (parentProps.tabs ? ActionConst.JUMP : ActionConst.PUSH);
if (type === 'switch') {
type = JUMP_ACTION;
type = ActionConst.JUMP;
}
const inheritProps = getInheritProps(parentProps);
const componentProps = component ? { component: wrapBy(component) } : {};
Expand Down Expand Up @@ -117,7 +122,7 @@ class Actions {
list = normalized; // normalize the list of scenes

const condition = el => (!el.props.component && !el.props.children && !el.props.onPress &&
(!el.props.type || el.props.type === REFRESH_ACTION));
(!el.props.type || ActionMap[el.props.type] === ActionConst.REFRESH));
// determine sub-states
let baseKey = root.key;
let subStateParent = parentProps.key;
Expand All @@ -135,7 +140,7 @@ class Actions {
baseKey = innerKey;
subStateParent = res.key;
const inner = { ...res, name: key, key: innerKey,
sceneKey: innerKey, type: PUSH_ACTION, parent: res.key };
sceneKey: innerKey, type: ActionConst.PUSH, parent: res.key };
refs[innerKey] = inner;
res.children = [innerKey];
delete res.component;
Expand All @@ -144,15 +149,15 @@ class Actions {
}
// process substates
for (const el of subStates) {
refs[el.key] = { key: el.key, name: el.key, ...el.props, type: REFRESH_ACTION,
refs[el.key] = { key: el.key, name: el.key, ...el.props, type: ActionConst.REFRESH,
base: baseKey, parent: subStateParent };
if (this[el.key]) {
console.log(`Key ${el.key} is already defined!`);
}
this[el.key] =
(props = {}) => {
assert(this.callback, 'Actions.callback is not defined!');
this.callback({ key: el.key, type: REFRESH_ACTION, ...filterParam(props) });
this.callback({ key: el.key, type: ActionConst.REFRESH, ...filterParam(props) });
};
}
if (this[key]) {
Expand All @@ -169,23 +174,23 @@ class Actions {
}

popTo(props = {}) {
return this.callback({ ...filterParam(props), type: POP_TO });
return this.callback({ ...filterParam(props), type: ActionConst.POP_TO });
}

pop(props = {}) {
return this.callback({ ...filterParam(props), type: POP_ACTION });
return this.callback({ ...filterParam(props), type: ActionConst.BACK_ACTION });
}

jump(props = {}) {
return this.callback({ ...filterParam(props), type: JUMP_ACTION });
return this.callback({ ...filterParam(props), type: ActionConst.JUMP });
}

refresh(props = {}) {
return this.callback({ ...filterParam(props), type: REFRESH_ACTION });
return this.callback({ ...filterParam(props), type: ActionConst.REFRESH });
}

focus(props = {}) {
return this.callback({ ...filterParam(props), type: FOCUS_ACTION });
return this.callback({ ...filterParam(props), type: ActionConst.FOCUS });
}

create(scene:Scene, wrapBy = x => x) {
Expand Down
66 changes: 30 additions & 36 deletions src/Reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,8 @@

/* eslint-disable no-param-reassign */

import {
PUSH_ACTION,
POP_ACTION2,
POP_TO,
JUMP_ACTION,
REPLACE_ACTION,
RESET_ACTION,
POP_ACTION,
REFRESH_ACTION,
} from './Actions';

import * as ActionConst from './ActionConst';
import { ActionMap } from './Actions';
import { assert } from './Util';
import { getInitialState } from './State';

Expand All @@ -37,7 +28,7 @@ function checkPropertiesEqual(action, lastAction) {
}

function inject(state, action, props, scenes) {
const condition = action.type === REFRESH_ACTION ? state.key === props.key ||
const condition = ActionMap[action.type] === ActionConst.REFRESH ? state.key === props.key ||
state.sceneKey === action.key : state.sceneKey === props.parent;
// console.log("INJECT:", action.key, state.sceneKey, condition);
if (!condition) {
Expand All @@ -58,8 +49,8 @@ function inject(state, action, props, scenes) {
}
let ind;

switch (action.type) {
case POP_TO: {
switch (ActionMap[action.type]) {
case ActionConst.POP_TO: {
const targetIndex = action.targetIndex;

return {
Expand All @@ -69,8 +60,8 @@ function inject(state, action, props, scenes) {
};
}

case POP_ACTION2:
case POP_ACTION: {
case ActionConst.BACK:
case ActionConst.BACK_ACTION: {
assert(!state.tabs, 'pop() operation cannot be run on tab bar (tabs=true)');
if (state.index === 0) {
return state;
Expand All @@ -97,7 +88,7 @@ function inject(state, action, props, scenes) {
children: state.children.slice(0, -1 * popNum),
};
}
case REFRESH_ACTION:
case ActionConst.REFRESH:
return props.base ?
{ navBar: state.navBar,
...scenes.rootProps,
Expand All @@ -109,7 +100,7 @@ function inject(state, action, props, scenes) {
key: state.key,
from: null,
};
case PUSH_ACTION:
case ActionConst.PUSH:
if (state.children[state.index].sceneKey === action.key && !props.clone
&& checkPropertiesEqual(action, state.children[state.index])) {
return state;
Expand All @@ -120,13 +111,13 @@ function inject(state, action, props, scenes) {
from: null,
children: [...state.children, getInitialState(props, scenes, state.index + 1, action)],
};
case JUMP_ACTION:
case ActionConst.JUMP:
assert(state.tabs, `Parent=${state.key} is not tab bar, jump action is not valid`);
ind = -1;
state.children.forEach((c, i) => { if (c.sceneKey === action.key) { ind = i; } });
assert(ind !== -1, `Cannot find route with key=${action.key} for parent=${state.key}`);
return { ...state, index: ind };
case REPLACE_ACTION:
case ActionConst.REPLACE:
if (state.children[state.index].sceneKey === action.key) {
return state;
}
Expand All @@ -139,7 +130,7 @@ function inject(state, action, props, scenes) {
);

return { ...state, children: state.children };
case RESET_ACTION:
case ActionConst.RESET:
if (state.children[state.index].sceneKey === action.key) {
return state;
}
Expand All @@ -159,7 +150,7 @@ function inject(state, action, props, scenes) {
}

function findElement(state, key, type) {
if ((type === REFRESH_ACTION && state.key === key) || state.sceneKey === key) {
if ((ActionMap[type] === ActionConst.REFRESH && state.key === key) || state.sceneKey === key) {
return state;
}
if (state.children) {
Expand Down Expand Up @@ -198,7 +189,7 @@ function reducer({ initialState, scenes }) {
assert(state.scenes, 'state.scenes is missed');

if (action.key) {
if (action.type === REFRESH_ACTION) {
if (ActionMap[action.type] === ActionConst.REFRESH) {
let key = action.key;
let child = findElement(state, key, action.type) || state.scenes[key];
let sceneKey = child.sceneKey;
Expand Down Expand Up @@ -230,15 +221,17 @@ function reducer({ initialState, scenes }) {
}
} else {
// set current route for pop action or refresh action
if (action.type === POP_ACTION || action.type === POP_ACTION2 ||
action.type === REFRESH_ACTION || action.type === POP_TO) {
if (ActionMap[action.type] === ActionConst.BACK_ACTION ||
ActionMap[action.type] === ActionConst.BACK ||
ActionMap[action.type] === ActionConst.REFRESH ||
ActionMap[action.type] === ActionConst.POP_TO) {
if (!action.key && !action.parent) {
action = { ...getCurrent(state), ...action };
}
}

// Find the parent and index of the future state
if (action.type === POP_TO) {
if (ActionMap[action.type] === ActionConst.POP_TO) {
const target = action.data;
assert(target, 'PopTo() must be called with scene name');

Expand All @@ -264,7 +257,8 @@ function reducer({ initialState, scenes }) {
}

// recursive pop parent
if (action.type === POP_ACTION || action.type === POP_ACTION2) {
if (ActionMap[action.type] === ActionConst.BACK_ACTION ||
ActionMap[action.type] === ActionConst.BACK) {
const parent = action.parent || state.scenes[action.key].parent;
let el = findElement(state, parent, action.type);
while (el.parent && (el.children.length <= 1 || el.tabs)) {
Expand All @@ -275,15 +269,15 @@ function reducer({ initialState, scenes }) {
}
}

switch (action.type) {
case POP_ACTION2:
case POP_ACTION:
case POP_TO:
case REFRESH_ACTION:
case PUSH_ACTION:
case JUMP_ACTION:
case REPLACE_ACTION:
case RESET_ACTION:
switch (ActionMap[action.type]) {
case ActionConst.BACK:
case ActionConst.BACK_ACTION:
case ActionConst.POP_TO:
case ActionConst.REFRESH:
case ActionConst.PUSH:
case ActionConst.JUMP:
case ActionConst.REPLACE:
case ActionConst.RESET:
return update(state, action);

default:
Expand Down
9 changes: 7 additions & 2 deletions src/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import React, {
} from 'react';
import NavigationExperimental from 'react-native-experimental-navigation';

import Actions from './Actions';
import Actions, { ActionMap } from './Actions';
import getInitialState from './State';
import Reducer from './Reducer';
import DefaultRenderer from './DefaultRenderer';
Expand Down Expand Up @@ -88,7 +88,12 @@ class Router extends Component {
}

Actions.callback = props => {
if (this.props.dispatch) this.props.dispatch(props);
if (props.type && ActionMap[props.type]) {
props.type = ActionMap[props.type];
}
if (this.props.dispatch) {
this.props.dispatch(props);
}
return onNavigate(props);
};

Expand Down
Loading

0 comments on commit e047499

Please sign in to comment.