vue-condition-watcher
Vue Composition API for automatic fetch data when condition has been changed
requires Node.js 12.0.0 or higher.
Features
✔ Auto fetch data when conditions changed.
✔ Auto filter falsy value in conditions.
✔ Auto converts the corresponding type. (string, number, array, date)
✔ Store the conditions within the URL hash every time a condition is changed
✔ Sync the state with the query string and initialize off of that and that back/forward/execute work.
✔ Keep requests first in — first out.
✔ Works for Vue 2 & 3 by the power of vue-demi
👉 Download Vue3 example here (Use Vite)
cd examples/vue3
yarn
yarn serve
👉 Download Vue2 @vue/composition-api example here
cd examples/vue2
yarn
yarn serve
👉 Online demo with vue-infinite-scroll
Quick Start
Simple example for vue-next and vue-router-next
createApp({
template: `
<div class=”filter”>
<input v-model=”conditions.name”>
<button @click=”execute”>Refetch</button>
</div>
<div class=”container” v-if=”!loading”>
{{ data }}
</div>
<div class=”loading” v-else>Loading…</div>
`,
setup() {
const config = {
fetcher: params => axios.get(‘/user/’, {params}),
conditions: {
name: ”
},
}
return useConditionWatcher(config, {sync: ‘router’})
},
})
.provide(‘router’, router)
.use(router)
.mount(document.createElement(‘div’))
Usage
In your project
yarn add vue-condition-watcher
Or with npm
npm install vue-condition-watcher
CDN
https://unpkg.com/vue-condition-watcher/dist/index.js
Basic Usage
const { conditions, data, error, loading, execute, resetConditions, onConditionsChange } = useConditionWatcher(config, queryOptions)
Execute Fetch
conditions is reactive proxy, easy execute fetch when conditions value changed
const { conditions } = useConditionWatcher({
fetcher,
conditions: {
page: 0
},
defaultParams: {
opt_expand: ‘date’
}
})
conditions.page = 1 // fetch data with payload { page: 1, opt_expand: ‘date’ }
conditions.page = 2 // fetch data with payload { page: 2, opt_expand: ‘date’ }
Just call execute function to send a request if you need.
const { conditions, execute: refetch } = useConditionWatcher({
fetcher,
conditions: {
page: 0
},
defaultParams: {
opt_expand: ‘date’
}
})
refetch() // fetch data with payload { page: 0, opt_expand: ‘date’ }
Update conditions one time.
const { conditions, resetConditions } = useConditionWatcher({
fetcher,
immediate: false,
conditions: {
page: 0,
name: ”,
date: []
},
})
// initial conditions then fire onConditionsChange event
Object.assign(conditions, {
name: ‘runkids’,
date: [‘2022-01-01’, ‘2022-01-02’]
})
// Reset conditions
function reset () {
Object.assign(conditions, {
page: 0,
name: ”,
date: []
})
// Or you can just use `resetConditions` function to initial value.
resetConditions()
}
Conditions Change Event
onConditionsChange can help you handle conditions changed.
Will return new value and old value.
const { conditions, onConditionsChange } = useConditionWatcher({
fetcher,
conditions: {
page: 0
},
})
conditions.page = 1
onConditionsChange((conditions, preConditions)=> {
console.log(conditions) // { page: 1}
console.log(preConditions) // { page: 0}
})
Fetch Event
The onFetchResponse, onFetchError and onFetchFinally will fire on fetch request.
const { onFetchResponse, onFetchError, onFetchFinally } = useConditionWatcher(config)
onFetchResponse((response) => {
console.log(response)
})
onFetchError((error) => {
console.error(error)
})
onFetchFinally(() => {
//todo
})
Prevent Request
Setting the immediate to false will prevent the request until the execute
function called or conditions changed.
const { execute } = useConditionWatcher({
fetcher,
conditions,
immediate: false,
})
execute()
Intercepting Request
The beforeFetch let you modify conditions before fetch, or you can call cancel function to stop fetch.
useConditionWatcher({
fetcher,
conditions: {
date: [‘2022/01/01’, ‘2022/01/02’]
},
initialData: [],
async beforeFetch(conditions, cancel) {
// await something
await doSomething ()
// conditions is an object clone copy from config.conditions
const {date, …baseConditions} = conditions
const [after, before] = date
baseConditions.created_at_after = after
baseConditions.created_at_before = before
return baseConditions
}
})
The afterFetch can intercept the response before data updated
const { data } = useConditionWatcher({
fetcher,
conditions,
async afterFetch(response) {
//response.data = {id: 1, name: ‘runkids’}
if(response.data === null) {
return []
}
const finalResponse = await otherAPIById(response.data.id)
return finalResponse // [{message: ‘Hello’, sender: ‘runkids’}]
}
})
console.log(data) //[{message: ‘Hello’, sender: ‘runkids’}]
The onFetchError can intercept the response before data and error updated
const { data, error } = useConditionWatcher({
fetcher,
conditions,
async onFetchError({data, error}) {
if(error.code === 401) {
await doSomething()
}
return {
data: [],
error: ‘Error Message’
}
}
})
console.log(data) //[]
console.log(error) //’Error Message’
More Configs
config : An object of config for vue-condition-watcher
fetcher (⚠️Required) : Can be any asynchronous function to fetch data
conditions (⚠️Required) : An object of conditions, also be initial value
defaultParams: An object of fetcher’s default
parameters
initialData: data default value is null, and you can setting data default value by use this config
immediate: Setting the immediate to false will prevent the request until the execute function called. immediate default is true.
const config = {
fetcher: params => axios.get(‘url’, { params }),
defaultParams: {
type: ‘member’
},
immediate: true,
initialData: []
conditions: {
offset: 0,
limit: 10,
username: ”,
},
}
queryOptions: An object of options to sync query string with conditions
⚠️ queryOptions work base on vue-router, you need install vue-router first.
sync: key of provide name ( String | Symbol )
main.js: register router
import {createApp} from ‘vue’
import App from ‘./App.vue’
import { router } from ‘./router’
const app = createApp(App)
.provide(‘router’, router) // it’s should be required
.use(router)
.mount(‘#app’)
then
useConditionWatcher(config, {sync: ‘router’})
ignore: you can ignore key name from conditions, will not push with query.
useConditionWatcher(config, {sync: ‘router’, ignore: [‘offset’, ‘limit’]})
navigation: use vue router navigation method push or replace, default value is push.
useConditionWatcher(config, {sync: ‘router’, navigation: ‘replace’})
How to use in vue@2 with @vue/composition-api
( Good ) Add provide in main.js
new Vue({
el: ‘#app’,
router,
store,
provide: {
router
},
render: h => h(App)
})
Add provide in current file
import { useConditionWatcher } from “vue-condition-watcher”;
import { provide } from “@vue/composition-api”;
import router from “@/router”;
import api from “../api”;
export default {
setup() {
provide(“router”, router);
const config = {
fetcher: api.users,
conditions: {
offset: 0,
limit: 9
}
};
return useConditionWatcher(config, {sync: ‘router’, ignore: [‘offset’, ‘limit’]});
}
};
How to use in Nuxt with @nuxtjs/composition-api
Add provide in current file
import { useConditionWatcher } from “vue-condition-watcher”;
import { defineComponent, useRoute, provide, useContext } from “@nuxtjs/composition-api”;
import api from “~/api”;
export default defineComponent({
setup() {
const route = useRoute();
const { app } = useContext();
provide(‘router’, app.router);
const config = {
fetcher: api.users,
conditions: {
offset: 0,
limit: 9
}
};
return useConditionWatcher(config, {sync: ‘router’, ignore: [‘offset’, ‘limit’]});
}
});
Return Values
conditions : An object and returns a reactive proxy of conditions
data: Data resolved by config.fetcher
error: Error thrown by config.fetcher
loading: Request is fetching
execute: The function to fetch data
resetConditions: Reset conditions to initial value
onConditionsChange: Will fire on conditions changed
onFetchSuccess: Will fire on fetch request success
onFetchError: Will fire on fetch request error
onFetchFinally: Will fire on fetch finished
Lifecycle
onConditionsChange
Fire new conditions value and old conditions value.
onConditionsChange((cond, preCond)=> {
console.log(cond)
console.log(preCond)
})
beforeFetch
You can modify conditions before fetch, or you can call second of arguments to stop fetch this time.
const { conditions } = useConditionWatcher({
fetcher,
conditions,
beforeFetch
})
async function beforeFetch(cond, cancel){
if(!cond.token) {
// stop fetch
cancel()
// will fire onConditionsChange again
conditions.token = await fetchToken()
}
return cond
})
afterFetch & onFetchSuccess
afterFetch fire before onFetchSuccess
afterFetch can modify data before update.
Type
Modify data before update
afterFetch
config
⭕️
onFetchSuccess
event
❌
<template>
{{ data?.detail }} <!– ‘xxx’ –>
</template>
const { data, onFetchSuccess } = useConditionWatcher({
fetcher,
conditions,
async afterFetch(response){
//response = { id: 1 }
const detail = await fetchDataById(response.id)
return detail // { id: 1, detail: ‘xxx’ }
})
})
onFetchSuccess((response)=> {
console.log(response) // { id: 1, detail: ‘xxx’ }
})
onFetchError(config) & onFetchError(event)
config.onFetchError fire before event.onFetchError
config.onFetchError can modify data and error before update.
Type
Modify data before update
Modify error before update
onFetchError
config
⭕️
⭕️
onFetchError
event
❌
❌
const { onFetchError } = useConditionWatcher({
fetcher,
conditions,
onFetchError(ctx){
return {
data: [],
error: ‘Error message.’
}
})
})
onFetchError((error)=> {
console.log(error) // origin error data
})
onFetchFinally
Will fire on fetch finished.
onFetchFinally(async ()=> {
//do something
})