Commit e562cc16 by Wee

refactor: use right lifecycle to do side effects

parent ce1597af
...@@ -11,7 +11,7 @@ import warning from 'tiny-warning' ...@@ -11,7 +11,7 @@ import warning from 'tiny-warning'
declare var __DEV__: boolean declare var __DEV__: boolean
function debugLog(message: any) { function debugLog(message: any) {
// console.log(message) console.log(message)
} }
function isEmptyChildren(children) { function isEmptyChildren(children) {
...@@ -26,6 +26,17 @@ interface IMatchOptions { ...@@ -26,6 +26,17 @@ interface IMatchOptions {
strict?: boolean strict?: boolean
sensitive?: boolean sensitive?: boolean
} }
enum SideEffect {
SAVE_DOM_SCROLL = 'SAVE_DOM_SCROLL',
CLEAR_DOM_DATA = 'CLEAR_DOM_SCROLL',
HIDE_DOM = 'HIDE_DOM',
SHOW_DOM = 'SHOW_DOM',
ON_REAPPEAR_HOOK = 'ON_REAPPEAR_HOOK',
ON_HIDE_HOOK = 'ON_HIDE_HOOK',
NO_SIDE_EFFECT = 'NO_SIDE_EFFECT'
}
enum LiveState { enum LiveState {
NORMAL_RENDER_MATCHED = 'normal matched render', NORMAL_RENDER_MATCHED = 'normal matched render',
NORMAL_RENDER_UNMATCHED = 'normal unmatched render (unmount)', NORMAL_RENDER_UNMATCHED = 'normal unmatched render (unmount)',
...@@ -63,31 +74,20 @@ class LiveRoute extends React.Component<PropsType, any> { ...@@ -63,31 +74,20 @@ class LiveRoute extends React.Component<PropsType, any> {
public scrollPosBackup: { left: number; top: number } | null = null public scrollPosBackup: { left: number; top: number } | null = null
public previousDisplayStyle: string | null = null public previousDisplayStyle: string | null = null
public liveState: LiveState = LiveState.NORMAL_RENDER_ON_INIT public liveState: LiveState = LiveState.NORMAL_RENDER_ON_INIT
public currentSideEffect: SideEffect[] = [SideEffect.NO_SIDE_EFFECT]
public componentDidMount() { public componentDidMount() {
this.getRouteDom() this.getRouteDom()
} }
// get route of DOM
public componentDidUpdate(prevProps, prevState) { public componentDidUpdate(prevProps, prevState) {
// if (!this.doesRouteEnableLive()) { this.performSideEffects(this.currentSideEffect, [SideEffect.ON_REAPPEAR_HOOK, SideEffect.CLEAR_DOM_DATA])
// return
// }
// // restore display when matched normally
// debugLog(this.liveState)
// if (this.liveState === LiveState.NORMAL_RENDER_MATCHED) {
// this.showRoute()
// this.restoreScrollPosition()
// this.clearScroll()
// }
// get DOM if match and render
this.getRouteDom() this.getRouteDom()
} }
// clear on unmounting // clear on unmounting
public componentWillUnmount() { public componentWillUnmount() {
this.clearDomData()
this.clearScroll() this.clearScroll()
} }
...@@ -177,13 +177,71 @@ class LiveRoute extends React.Component<PropsType, any> { ...@@ -177,13 +177,71 @@ class LiveRoute extends React.Component<PropsType, any> {
return null return null
} }
public performSideEffects = (sideEffects: SideEffect[], range: SideEffect[]) => {
const sideEffectsToRun = sideEffects.filter(item => range.includes(item))
sideEffectsToRun.forEach((sideEffect, index) => {
switch (sideEffect) {
case SideEffect.SAVE_DOM_SCROLL:
this.saveScrollPosition()
break
case SideEffect.HIDE_DOM:
this.hideRoute()
break
case SideEffect.ON_REAPPEAR_HOOK:
this.onHook('onReappear')
break
case SideEffect.ON_HIDE_HOOK:
this.onHook('onHide')
break
case SideEffect.CLEAR_DOM_DATA:
this.clearScroll()
this.clearDomData()
break
}
})
this.currentSideEffect = sideEffects.filter(item => !range.includes(item)) as SideEffect[]
}
public getSnapshotBeforeUpdate(prevProps, prevState) {
this.performSideEffects(this.currentSideEffect, [SideEffect.SAVE_DOM_SCROLL, SideEffect.HIDE_DOM])
}
public onHook = (hookName: 'onHide' | 'onReappear') => {
const {
exact = false,
sensitive = false,
strict = false,
path,
livePath,
alwaysLive,
// from withRouter, same as RouterContext.Consumer ⬇️
history,
location,
match,
staticContext
// from withRouter, same as RouterContext.Consumer ⬆️
} = this.props
const hook = this[hookName]
const context = { history, location, match, staticContext }
const matchOfPath = this.props.path ? matchPath(location.pathname, this.props) : context.match
const matchOfLivePath = this.isLivePathMatch(livePath, alwaysLive, location!.pathname, {
path,
exact,
strict,
sensitive
})
const matchAnyway = matchOfPath || matchOfLivePath
if (typeof hook === 'function') {
hook(location!, matchAnyway, history, livePath, alwaysLive)
}
}
public render() { public render() {
const { const {
exact = false, exact = false,
sensitive = false, sensitive = false,
strict = false, strict = false,
onReappear,
onHide,
forceUnmount, forceUnmount,
path, path,
livePath, livePath,
...@@ -199,7 +257,7 @@ class LiveRoute extends React.Component<PropsType, any> { ...@@ -199,7 +257,7 @@ class LiveRoute extends React.Component<PropsType, any> {
} = this.props } = this.props
let { children } = this.props let { children } = this.props
const context = { history, location, match, staticContext } const context = { history, location, match, staticContext }
invariant(context, 'You should not use <Route> outside a <Router>') invariant(!!context, 'You should not use <Route> outside a <Router>')
const matchOfPath = this.props.path ? matchPath(location.pathname, this.props) : context.match const matchOfPath = this.props.path ? matchPath(location.pathname, this.props) : context.match
const matchOfLivePath = this.isLivePathMatch(livePath, alwaysLive, location!.pathname, { const matchOfLivePath = this.isLivePathMatch(livePath, alwaysLive, location!.pathname, {
...@@ -231,36 +289,27 @@ class LiveRoute extends React.Component<PropsType, any> { ...@@ -231,36 +289,27 @@ class LiveRoute extends React.Component<PropsType, any> {
// hide ➡️ show // hide ➡️ show
if (this.liveState === LiveState.HIDE_RENDER) { if (this.liveState === LiveState.HIDE_RENDER) {
if (typeof onReappear === 'function') { this.currentSideEffect = [SideEffect.ON_REAPPEAR_HOOK]
onReappear(location!, matchAnyway, history, livePath, alwaysLive)
}
} }
this.liveState = LiveState.NORMAL_RENDER_MATCHED this.liveState = LiveState.NORMAL_RENDER_MATCHED
} else { } else {
debugLog('--- hide match ---') debugLog('--- hide match ---')
// force unmount // force unmount
if (typeof forceUnmount === 'function' && forceUnmount(location, match, history, livePath, alwaysLive)) { if (typeof forceUnmount === 'function' && forceUnmount(location, match, history, livePath, alwaysLive)) {
this.liveState = LiveState.NORMAL_RENDER_UNMATCHED this.liveState = LiveState.NORMAL_RENDER_UNMATCHED
this.clearScroll() this.currentSideEffect = [SideEffect.CLEAR_DOM_DATA]
this.clearDomData()
return null return null
} }
// show ➡️ hide // show ➡️ hide
if (this.liveState === LiveState.NORMAL_RENDER_MATCHED) { if (this.liveState === LiveState.NORMAL_RENDER_MATCHED) {
if (typeof onHide === 'function') { this.currentSideEffect = [SideEffect.ON_HIDE_HOOK, SideEffect.SAVE_DOM_SCROLL, SideEffect.HIDE_DOM]
onHide(location!, matchAnyway, history, livePath, alwaysLive)
}
this.saveScrollPosition()
this.hideRoute()
} }
this.liveState = LiveState.HIDE_RENDER this.liveState = LiveState.HIDE_RENDER
} }
// normal render // normal render
const props = { ...context, location, match: matchOfPath, ensureDidMount: this.getRouteDom } const props = { ...context, location, match: matchOfPath, ensureDidMount: this.getRouteDom }
// const props = { history, staticContext, location, match: matchAnyway }
// Preact uses an empty array as children by // Preact uses an empty array as children by
// default, so use null if that's the case. // default, so use null if that's the case.
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"outDir": "dist/", "outDir": "dist/",
"module": "commonjs", "module": "commonjs",
"target": "es5", "target": "es5",
"lib": ["es6", "dom"], "lib": ["es2017", "dom"],
"sourceMap": true, "sourceMap": true,
"jsx": "react", "jsx": "react",
"moduleResolution": "node", "moduleResolution": "node",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment