New functionality extention of useRefHistory in VueUse library
Tags: vue, javascript, webdev, vueuse
Published: 2021-09-15 15:58:42

I would like to share with you my little joy. My suggestion for expanding the function `useRefHistory` by adding the delay effect to history snapshots was accepted by maintainers of VueUse. They trusted me to write a pull request. The new functionality is already available in VueUse (since version 6.3.3). But first things first.

## Adventure story

In my [last article](https://dev.to/harmyderoman/vueuse-as-must-have-library-for-vue-3-5o2), I wrote about `useRefHistory` and how to implement it in your application. Using the `useRefHistory` function, I noticed that its usability is not perfect. This function takes a snapshot of the data every time the slightest change occurs, even if it's just one letter. If you are writing a long text or a to-do list, make a mistake, and want to revert the changes, it is very inconvenient to press Undo for each letter. It would be better if the changes were saved with a small time delay.

I started looking for a solution. It seems that it lies on the surface - you just need to add `setTimeOut` to the `watch` which monitors data changes, but it turned out that this was not enough. `watch` also needs to skip changes that the `undo` and `redo` methods do to data, otherwise, this creates complete chaos!!!

Looking for a solution led me to the source code of the VueUse library itself. It turned out that the mechanisms for such functionality had already been laid down by the authors.

I opened a [issue](https://github.com/vueuse/vueuse/issues/732) in the VueUse repository with a suggestion to add a new feature. The maintainers Anthony and Patak were very nice and professional. They supported my idea and entrusted me to write a pull request. They suggested to me how to implement it in the best way without breaking the style of the library. As a result, we came to a solution.

After the code review and some edits, the pull request was merged. Right now new functions already are available to you. Now I will tell you how to use them.

## [useDebouncedRefHistory](https://vueuse.org/core/useDebouncedRefHistory/)

The main change I made in the `useRefHistory` functions is that now you can pass the `eventFilter` property in the options object to change the behavior of the function. Filters are internal helper structures of the library that you don't really need to learn. Unless you decide to contribute some code for VueUse by yourself. So, let's go straight to the practical.

`useDebouncedRefHistory` records the history of data changes with a specified delay. The delay is set in milliseconds and is passed to the options object. It can be wrapped in a ref object, then the delay will become reactive.

```html
<script lang="ts">
  import { defineComponent, ref } from "vue"
  import { useDebouncedRefHistory } from "@vueuse/core"

  export default defineComponent({
    setup() {
      const note = ref({
        title: "",
        todos: []
      })

      const { undo, redo, canUndo, canRedo, clear } = useDebouncedRefHistory(
        note,
        { deep: true, clone: true, debounce: 1000 }
      )

      return {
        note,
        undo,
        redo,
        canUndo,
        canRedo,
        clear
      }
    }
  })
</script>
```

## [useThrottledRefHistory](https://vueuse.org/core/useThrottledRefHistory/)

This function is similar to the previous one, only with a throttle effect. This means that the history will be saved at the moment of data was changed, and the next time after the delay time passed. If the user doesn't stop making changes, they will be recorded every 1000 milliseconds. For example:

```html
<!-- setup in script - some syntactic sugar that will make your life easier-->
<script setup>
  import { ref } from "vue"
  import { useThrottledRefHistory } from "@vueuse/core"

  const delay = ref(1000)
  const count = ref(0)

  const { history, undo, redo, canUndo, canRedo } = useThrottledRefHistory(
    count,
    { throttle: delay }
  )
</script>
```

**Update:** (since version 6.4.0) a new property `trailing` now is available in the options (`true` by default). It determines whether to record history at the end of the time delay. If you want the watcher to react only to the first change, and then freeze the observation for a given time, then set `trailing` to `false`. Like this:

```javascript
const DataHistory = useThrottledRefHistory(data, {
  throttle: 300,
  trailing: false
})
```

## Conclusion

As you can see, the changes are not so vast in the codebase and logic, but they significantly improve the user experience. Use it wisely.

I find it very important to contribute our code to open source projects because we all use other people's work. Everyone can make a little assist to OS. This is what drives our industry further. In addition, this is an opportunity to work with world-class programmers and inherit some experience.

After all, it's nice to know that your code will be used by thousands of developers around the world.