redux-first-router
Version:
think of your app in states not routes (and, yes, while keeping the address bar in sync)
88 lines (77 loc) • 2.33 kB
Flow
// @flow
import type {
RoutesMap,
Location,
Action,
ReceivedAction,
History,
QuerySerializer
} from '../flow-types'
import actionToPath from '../pure-utils/actionToPath'
import nestAction from '../pure-utils/nestAction'
import { NOT_FOUND } from '../index'
const __DEV__ = process.env.NODE_ENV !== 'production'
export default (
action: Object,
routesMap: RoutesMap,
prevLocation: Location,
history: History,
notFoundPath: string,
serializer?: QuerySerializer
): Action => {
try {
const pathname = actionToPath(action, routesMap, serializer)
const kind = getKind(!!history.entries, pathname, history, action)
return nestAction(pathname, action, prevLocation, history, kind)
}
catch (e) {
if (__DEV__) {
console.error('[redux-first-router] Internal exception when parsing action, fallback to NOT_FOUND. Original exception: ', e)
}
const payload = { ...action.payload }
return nestAction(
notFoundPath || prevLocation.pathname || '/',
{ ...action, type: NOT_FOUND, payload },
prevLocation,
history
)
}
}
// REACT NATIVE FEATURE:
// emulate npm `history` package and `historyCreateAction` so that actions
// and state indicate the user went back or forward. The idea is if you are
// going back or forward to a route you were just at, apps can determine
// from `state.location.kind === 'back|next'` and `action.kind` that things like
// scroll position should be restored.
// NOTE: for testability, history is also returned to make this a pure function
const getKind = (
isMemoryHistory: boolean,
pathname: string,
history: History,
action: ReceivedAction
): ?string => {
const kind = action.meta && action.meta.location && action.meta.location.kind
if (kind) {
return kind
}
else if (!isMemoryHistory) {
return 'push'
}
if (goingBack(history, pathname)) {
history.index--
return 'back'
}
else if (goingForward(history, pathname)) {
history.index++
return 'next'
}
return 'push'
}
const goingBack = (hist: History, path: string): boolean => {
const prev = hist.entries[hist.index - 1]
return prev && prev.pathname === path
}
const goingForward = (hist: History, path: string): boolean => {
const next = hist.entries[hist.index + 1]
return next && next.pathname === path
}