DEV Community

Cover image for New functionality extention of useRefHistory in VueUse library
Roman Garmider 💛💙
Roman Garmider 💛💙

Posted on • Updated on

New functionality extention of useRefHistory in VueUse library

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, 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 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

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.

<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>
Enter fullscreen mode Exit fullscreen mode

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:

<!-- 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>
Enter fullscreen mode Exit fullscreen mode

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:

const DataHistory = useThrottledRefHistory(data, {
  throttle: 300,
  trailing: false
})
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)