Few weeks ago I was browsing up dev.to to look up some references for custom hook in react, and found this great article https://dev.to/gabe_ragland/debouncing-with-react-hooks-jci . I also heard that vue 3 is coming with similar API with react hooks called compostion API
and that part already available in https://www.npmjs.com/package/@vue/composition-api for Vue 2. Lets try to create similar thing there using vue new feature.
- Create a new vue project (you can look up to google on how to do this)
- Install https://www.npmjs.com/package/@vue/composition-api by running
npm i @vue/composition-api -S
- Run the project with
npm run serve
- In the main.js we need to info vue to use the composition api plugin, otherwise it won't compile the new syntax correctly
import Vue from 'vue'
import App from './App.vue'
import VueCompositionApi from "@vue/composition-api";
Vue.use(VueCompositionApi);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
- Create a new component in components folder called
DebouncedInput.vue
and copy the following code
<template>
<div>
<input :value="displayValue" @input="debounceListener" placeholder="search here" />
<p>deb : {{ debouncedValue }}</p>
</div>
</template>
<script>
import { ref } from "@vue/composition-api";
export default {
setup() {
let timeoutRef = null;
const displayValue = ref("");
const debouncedValue = ref("");
const debounceListener = e => {
if (timeoutRef !== null) {
clearTimeout(timeoutRef);
}
displayValue.value = e.target.value;
timeoutRef = setTimeout(() => {
debouncedValue.value = e.target.value;
}, 800);
};
return { debouncedValue, displayValue, debounceListener };
}
};
</script>
Ok, what was that huh? seems strange for usual vue file. its the new composition API syntax which allow us to write our logic code more modular / functional you can look up for more info here https://composition-api.vuejs.org/. Okay now we break down few things about code above
import { ref } from "@vue/composition-api";
in this line we import our ref
function from the plugin, basically, it will turn our variables into a reactive variable (like useState in react hooks).
let timeoutRef = null;
const displayValue = ref("");
const debouncedValue = ref("");
here is how we create the reactive data. timeourRef
is a helper variable that we will use to maintain our timeout and won't be used in view, so no need to be reactive.
const debounceListener = e => {
if (timeoutRef !== null) {
clearTimeout(timeoutRef);
}
displayValue.value = e.target.value;
timeoutRef = setTimeout(() => {
debouncedValue.value = e.target.value;
}, 800);
};
this is the main function, basically it just delay the process to set the debouncedValue
and clear the timeout if there is a previous timeout but new event input is already typed.
return { debouncedValue, displayValue, debounceListener };
finally we return all the reactive variable and the function.
Now we have a usable component with new composition api. but this is the same behaviour like previous vue syntax that we need to share the logic and the view as a component. What if like we need to just reuse the logic only? this is where this new syntax comes in handy.
Reusable logic
Now create a new file called useDebounce.js
inside src/composed
folder. then use the following code
import { ref } from "@vue/composition-api";
export default function (timeoutCount = 800) {
let timeoutRef = null;
const displayValue = ref("");
const debouncedValue = ref("");
const debounceListener = e => {
if (timeoutRef !== null) {
clearTimeout(timeoutRef);
}
displayValue.value = e.target.value;
timeoutRef = setTimeout(() => {
debouncedValue.value = e.target.value;
}, timeoutCount);
};
return { debouncedValue, displayValue, debounceListener };
}
basically it is almost like the prev component but we wrap it inside a function (oh maybe this is called functional approach?) then we pass a parameter to easily customize how long we wanna wait for the timeout. Then in our previous component, we can update the code to be like
<template>
<div>
<input :value="displayValue" @input="debounceListener" placeholder="search here" />
<p>deb : {{ debouncedValue }}</p>
</div>
</template>
<script>
import useDebounce from "../composed/useDebounce";
export default {
setup() {
return {
...useDebounce(2000)
};
}
};
</script>
wow so much cleaner, and we can mix and match other logic inside our component.
Conclusion
Reusable code is one of the signs of good code, as more and more duplicated code lives in our codebase will make our codebase harder to maintain. Really look up for this composition api to be ready to use in vue 3.
please let me know your thoughts or if have other possible cool use cases to use this cool feature. If you find my explanation hard to follow can also look up to the code in my github https://github.com/heruujoko/use-debounce-vue
Top comments (0)