Skip to content

Commit f997f31

Browse files
committed
fix: history back and forward bug
1 parent 9bdca25 commit f997f31

File tree

7 files changed

+132
-96
lines changed

7 files changed

+132
-96
lines changed

examples/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"dependencies": {
99
"vue": "^3.0.0-beta.18",
1010
"vue-condition-watcher": "^0.0.11",
11-
"vue-router": "^4.0.0-alpha.13"
11+
"vue-router": "^4.0.0-beta.1"
1212
},
1313
"devDependencies": {
1414
"@vue/compiler-sfc": "^3.0.0-beta.18",

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@
5353
]
5454
},
5555
"dependencies": {
56-
"vue-demi": "^0.1.3",
57-
"rfdc": "^1.1.4"
56+
"vue-demi": "^0.1.3"
5857
},
5958
"devDependencies": {
6059
"@types/jest": "24.0.20",
@@ -73,7 +72,8 @@
7372
"ts-jest": "24.1.0",
7473
"typescript": "^3.9.2",
7574
"vue": "^3.0.0-beta.18",
76-
"vue-router": "^4.0.0-alpha.13"
75+
"vue-router": "^4.0.0-beta.1",
76+
"rfdc": "^1.1.4"
7777
},
7878
"peerDependencies": {
7979
"vue": "^3.0.0-beta.18"

src/types.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
import { Ref, InjectionKey } from 'vue-demi'
2+
13
export type ConditionsType = {
24
[propName: string]: any
35
}
6+
7+
export type FetcherType = (params: ConditionsType) => Promise<any>
8+
export type ProvideKeyName<T> = InjectionKey<T> | string
9+
10+
export interface QueryOptions<T> {
11+
sync?: ProvideKeyName<T>
12+
ignore?: string[]
13+
}
14+
15+
export interface Config {
16+
fetcher: FetcherType
17+
conditions: ConditionsType
18+
defaultParams?: ConditionsType
19+
beforeFetch?: (conditions: ConditionsType) => ConditionsType
20+
}
21+
22+
export interface ResultInterface {
23+
conditions: { [x: string]: any }
24+
loading: Ref<boolean | false>
25+
data: Ref<any | null>
26+
refresh: Ref<() => void>
27+
error: Ref<any | null>
28+
}

src/useConditionWatcher.ts

Lines changed: 31 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,15 @@
1-
import { reactive, toRefs, ref, watch, Ref, watchEffect, inject, InjectionKey } from 'vue-demi'
2-
import { ConditionsType } from './types'
1+
import { reactive, ref, watch, watchEffect, inject, onMounted, onUnmounted } from 'vue-demi'
2+
import { ConditionsType, Config, QueryOptions, ResultInterface } from './types'
33
import { filterNoneValueObject, createParams, stringifyQuery, syncQuery2Conditions } from './utils'
4+
import { useFetchData } from './useFetchData'
5+
import { useParseQuery } from './useParseQuery'
46
import clone from 'rfdc'
5-
import { Router } from 'vue-router'
6-
7-
type FetcherType = (params: ConditionsType) => Promise<any>
8-
type ProvideKeyName<T> = InjectionKey<T> | string
9-
10-
interface QueryOptions<T> {
11-
sync?: ProvideKeyName<T>
12-
ignore?: string[]
13-
}
14-
15-
interface Config {
16-
fetcher: FetcherType
17-
conditions: ConditionsType
18-
defaultParams?: ConditionsType
19-
beforeFetch?: (conditions: ConditionsType) => ConditionsType
20-
}
21-
22-
interface ResultInterface {
23-
conditions: { [x: string]: any }
24-
loading: Ref<boolean | false>
25-
data: Ref<any | null>
26-
refresh: Ref<() => void>
27-
error: Ref<any | null>
28-
}
297

308
export default function useConditionWatcher<T extends Config, E extends QueryOptions<E>>(
319
config: T,
3210
queryOptions?: E
3311
): ResultInterface {
34-
let router: Router
12+
let router = null
3513
const _conditions = reactive(config.conditions)
3614
const loading = ref(false)
3715
const data = ref(null)
@@ -40,6 +18,13 @@ export default function useConditionWatcher<T extends Config, E extends QueryOpt
4018
const query = ref({})
4119
const completeInitialConditions = ref(false)
4220

21+
const syncConditionsByQuery = () => {
22+
const { query: initQuery } = useParseQuery()
23+
console.log('initQuery== ', initQuery)
24+
syncQuery2Conditions(_conditions, initQuery)
25+
completeInitialConditions.value = true
26+
}
27+
4328
const fetch = (conditions: ConditionsType): void => {
4429
const { loading: fetchLoading, result: fetchResult, error: fetchError, use: fetchData } = useFetchData(() =>
4530
config.fetcher(conditions)
@@ -90,42 +75,30 @@ export default function useConditionWatcher<T extends Config, E extends QueryOpt
9075
}
9176
)
9277

93-
if (
94-
queryOptions &&
95-
(typeof queryOptions.sync === 'string' || typeof queryOptions.sync === 'function') &&
96-
queryOptions.sync.length
97-
) {
78+
if (queryOptions && typeof queryOptions.sync === 'string' && queryOptions.sync.length) {
9879
router = inject(queryOptions.sync)
99-
if (router && router.isReady) {
100-
router.isReady().then(() => {
101-
// watch query changed
102-
watch(query, async () => {
103-
const path: string = router.currentRoute.value.path
104-
const queryString = stringifyQuery(query.value, queryOptions.ignore || [])
105-
completeInitialConditions.value = false
106-
await router.push(path + '?' + queryString)
107-
})
80+
if (router) {
81+
// initial conditions by window.location.search. just do once.
82+
syncConditionsByQuery()
83+
// watch query changed
84+
watch(query, async () => {
85+
const path: string = router.currentRoute.value.path
86+
const queryString = stringifyQuery(query.value, queryOptions.ignore || [])
87+
await router.push(path + '?' + queryString)
88+
})
89+
90+
onMounted(() => {
91+
window.addEventListener('popstate', syncConditionsByQuery)
92+
})
93+
onUnmounted(() => {
94+
window.removeEventListener('popstate', syncConditionsByQuery)
10895
})
109-
// watch router changed
110-
watch(
111-
router.currentRoute,
112-
(currentRoute, preCurrentRoute) => {
113-
const oldFullPath = preCurrentRoute ? preCurrentRoute.fullPath : ''
114-
if (currentRoute.fullPath !== oldFullPath) {
115-
//back/forward page sync query string to _conditions
116-
syncQuery2Conditions(_conditions, currentRoute.query)
117-
completeInitialConditions.value = true
118-
}
119-
},
120-
{
121-
immediate: true,
122-
}
123-
)
12496
} else {
125-
throw new ReferenceError('[vue-condition-watcher] Could not found vue-router instance.')
97+
throw new ReferenceError(
98+
`[vue-condition-watcher] Could not found vue-router instance. Please check key: ${queryOptions.sync} is right!`
99+
)
126100
}
127101
}
128-
129102
completeInitialConditions.value = true
130103

131104
return {
@@ -136,33 +109,3 @@ export default function useConditionWatcher<T extends Config, E extends QueryOpt
136109
error,
137110
}
138111
}
139-
140-
function useFetchData<T>(fetcher: () => Promise<T>) {
141-
const state = reactive({
142-
loading: false,
143-
error: null,
144-
result: null,
145-
})
146-
147-
let lastPromise: Promise<T>
148-
const use = async () => {
149-
state.error = null
150-
state.loading = true
151-
const promise = (lastPromise = fetcher())
152-
try {
153-
const result = await promise
154-
if (lastPromise === promise) {
155-
state.result = result
156-
}
157-
} catch (e) {
158-
state.error = e
159-
} finally {
160-
state.loading = false
161-
}
162-
}
163-
164-
return {
165-
...toRefs(state),
166-
use,
167-
}
168-
}

src/useFetchData.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { reactive, toRefs } from 'vue-demi'
2+
3+
export function useFetchData<T>(fetcher: () => Promise<T>) {
4+
const state = reactive({
5+
loading: false,
6+
error: null,
7+
result: null,
8+
})
9+
10+
let lastPromise: Promise<T>
11+
const use = async () => {
12+
state.error = null
13+
state.loading = true
14+
const promise = (lastPromise = fetcher())
15+
try {
16+
const result = await promise
17+
if (lastPromise === promise) {
18+
state.result = result
19+
}
20+
} catch (e) {
21+
state.error = e
22+
} finally {
23+
state.loading = false
24+
}
25+
}
26+
27+
return {
28+
...toRefs(state),
29+
use,
30+
}
31+
}

src/useParseQuery.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
function decode(text: string | number): string {
2+
try {
3+
return decodeURIComponent('' + text)
4+
} catch (err) {
5+
console.error(`Error decoding "${text}".`)
6+
}
7+
return '' + text
8+
}
9+
10+
function parseQuery(search: string) {
11+
const query = {}
12+
if (search === '' || search === '?') return query
13+
const hasLeadingIM = search[0] === '?'
14+
const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&')
15+
for (let i = 0; i < searchParams.length; ++i) {
16+
let [key, rawValue] = searchParams[i].split('=') as [string, string | undefined]
17+
key = decode(key)
18+
let value = rawValue == null ? null : decode(rawValue)
19+
if (key in query) {
20+
let currentValue = query[key]
21+
if (!Array.isArray(currentValue)) {
22+
currentValue = query[key] = [currentValue]
23+
}
24+
currentValue.push(value)
25+
} else {
26+
query[key] = value
27+
}
28+
}
29+
return query
30+
}
31+
32+
export function useParseQuery(queryString?: string) {
33+
let query = queryString ? queryString : window.location.search.substring(1)
34+
return {
35+
query: parseQuery(query),
36+
}
37+
}

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4502,10 +4502,10 @@ vue-demi@^0.1.3:
45024502
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.1.3.tgz#e16321d20b025e95227fba01607f86e1fc9726e4"
45034503
integrity sha512-0h9/PwtrJx8oZeOd4ftGNlpnWUxp9HoGy+Wengw4pvdUi0o1+PLMaCpoQZ9tNGnTom8cz90M1ydxJgJg3InCpA==
45044504

4505-
vue-router@^4.0.0-alpha.13:
4506-
version "4.0.0-alpha.14"
4507-
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.0-alpha.14.tgz#4bc5fed1db61b8d04fd95ad9c499c7428f039a0e"
4508-
integrity sha512-ydWSXxXAsTCiJ31V4x4ZAKI1CdpPMhf7b2LPi4AmG5SCgduu1zf+LhzWWHXmgbmheEiJpfecigVIZp4ABpZJmw==
4505+
vue-router@^4.0.0-beta.1:
4506+
version "4.0.0-beta.1"
4507+
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.0-beta.1.tgz#8ccdc37c991efa30d1519f885dd772307715503a"
4508+
integrity sha512-byqdBiKISN9Qrse6A0fgR6tePQNwlAdx+wBgO2x08MEn6hy8ds19uKvosfruVjw5vhpFmjvGR15Z68an+7fRAQ==
45094509

45104510
vue@*:
45114511
version "2.6.11"

0 commit comments

Comments
 (0)