Skip to content

Commit

Permalink
feat($scrollRestoration): add feature to disable automatic scroll res…
Browse files Browse the repository at this point in the history
…toration via manual: true optio
  • Loading branch information
faceyspacey committed May 7, 2017
1 parent d0f305a commit 56166a8
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 55 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ module.exports = {
'no-unused-vars': 1,
'import/no-unresolved': 1,
'flowtype/no-weak-types': 1,
'consistent-return': 1,
semi: [2, 'never'],
'no-console': [2, { allow: ['warn', 'error'] }],
'flowtype/semi': [2, 'never'],
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ and you're free to make your own. Basically it passes the `href` on to **Redux F
into a URL for you! The package is obvious enough once you get the hang of what's going on here--check it
out when you're ready: [redux-first-router-link](http://github.com/faceyspacey/redux-first-router-link). And if
you're wondering, we don't offer route matching components like *React Router*--that's what state is for!
See our FAQ below.
See our [FAQ](#faq) below.

## routesMap

Expand Down
68 changes: 32 additions & 36 deletions src/action-creators/middlewareCreateAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ export default (
action: Object,
routesMap: RoutesMap,
prevLocation: Location,
history: History
hist: History
): Action => {
try {
const pathname = actionToPath(action, routesMap)
const kind = getKind(pathname, history)
const [kind, history] = getKindAndHistory(!!hist.entries, pathname, hist)
return nestAction(pathname, action, prevLocation, history, kind)
}
catch (e) {
Expand All @@ -25,49 +25,45 @@ export default (
pathname,
{ type: NOT_FOUND, payload },
prevLocation,
history
hist
)
}
}

const getKind = (pathname: string, history: History): ?string => {
const isMemoryHistory = !!history.entries

// 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.backNext` and `action.backNext` that things like
// scroll position should be restored.
// NOTE: for testability, history is also returned to make this a pure function
const getKindAndHistory = (
isMemoryHistory: boolean,
pathname: string,
history: History
): [?string, History] => {
if (!isMemoryHistory) {
return undefined
return [undefined, history]
}

const isLast = history.index === history.length - 1
const prev = history.entries[history.index - 1]
// 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.backNext` and `action.backNext` that things like
// scroll position should be restored.
if (isLast && prev) {
const prevPath = prev.pathname
const isGoingBack = prevPath === pathname

if (isGoingBack) {
history.index--
return 'backNext'
}

return undefined
if (goingBack(pathname, history)) {
history.index--
return ['backNext', history]
}
else if (goingForward(pathname, history)) {
history.index++
return ['backNext', history]
}

const next = history.entries[history.index + 1]

if (next) {
const nextPath = next.pathname
const isGoingForward = nextPath === pathname
return [undefined, history]
}

if (isGoingForward) {
history.index++
return 'backNext'
}
}
const goingBack = (pathname: string, history: History): boolean => {
const prev = history.entries[history.index - 1]
return prev && prev.pathname === pathname
}

return undefined
const goingForward = (pathname: string, history: History): boolean => {
const next = history.entries[history.index + 1]
return next && next.pathname === pathname
}
36 changes: 18 additions & 18 deletions src/connectRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,22 +277,8 @@ export default (

history.listen(_historyAttemptDispatchAction.bind(null, store))

_updateScroll = () => {
if (scrollBehavior) {
scrollBehavior.updateScroll(prevState, nextState)
}
else if (process.env.NODE_ENV !== 'production') {
throw new Error(
`[redux-first-router] you must set the \`restoreScroll\` option before
you can call \`updateScroll\``
)
}
}

// update the scroll position after initial rendering of page
if (scrollBehavior) {
setTimeout(_updateScroll, 0)
}
setTimeout(() => _updateScroll(false))

// dispatch the first location-aware action so initial app state is based on the url on load
if (!location.hasSSR || isServer()) {
Expand Down Expand Up @@ -337,14 +323,28 @@ export default (
}
}

if (scrollBehavior) {
_updateScroll()
}
_updateScroll(false)
}

/* SIDE_EFFECTS - client-only state that must escape closure */

_history = history
_scrollBehavior = scrollBehavior

_updateScroll = (performedByUser: boolean = true) => {
if (scrollBehavior) {
if (!scrollBehavior.manual) {
scrollBehavior.updateScroll(prevState, nextState)
}
}
else if (process.env.NODE_ENV !== 'production' && performedByUser) {
throw new Error(
`[redux-first-router] you must set the \`restoreScroll\` option before
you can call \`updateScroll\``
)
}
}

/* RETURN */

return {
Expand Down

0 comments on commit 56166a8

Please sign in to comment.