JAVASCRIPT

Advanced Undo/Redo for Reactive State with Vue 3 Composable

Build a robust undo/redo functionality for any reactive state in Vue 3 using a custom composable, enabling history tracking and state restoration.

// composables/useUndoRedo.js
import { ref, watch, computed } from 'vue';

export function useUndoRedo(initialValue) {
  const history = ref([initialValue]);
  const currentIndex = ref(0);

  const state = ref(initialValue);

  // Watch for changes in the state and add to history
  watch(state, (newValue) => {
    // If we're not at the end of history (i.e., we've undone some changes),
    // truncate the history and add the new change.
    if (currentIndex.value < history.value.length - 1) {
      history.value = history.value.slice(0, currentIndex.value + 1);
    }
    history.value.push(newValue);
    currentIndex.value = history.value.length - 1;
  }, { deep: true });

  const canUndo = computed(() => currentIndex.value > 0);
  const canRedo = computed(() => currentIndex.value < history.value.length - 1);

  const undo = () => {
    if (canUndo.value) {
      currentIndex.value--;
      state.value = history.value[currentIndex.value];
    }
  };

  const redo = () => {
    if (canRedo.value) {
      currentIndex.value++;
      state.value = history.value[currentIndex.value];
    }
  };

  return {
    state,
    undo,
    redo,
    canUndo,
    canRedo,
  };
}

// src/App.vue
<template>
  <div>
    <h1>Undo/Redo Example</h1>
    <textarea v-model="editorState.text" rows="5" cols="50"></textarea>
    <div>
      <button @click="undo()" :disabled="!canUndo">Undo</button>
      <button @click="redo()" :disabled="!canRedo">Redo</button>
    </div>
    <p>Current Text: {{ editorState.text }}</p>
  </div>
</template>

<script setup>
import { useUndoRedo } from './composables/useUndoRedo';

const { state: editorState, undo, redo, canUndo, canRedo } = useUndoRedo({ text: '' });

// Example: you can also directly modify editorState.text, and it will be tracked
// editorState.value.text = 'Some new text';
</script>
How it works: This snippet presents a powerful `useUndoRedo` composable for Vue 3 that provides undo/redo capabilities for any reactive state. It maintains a `history` array of state snapshots and a `currentIndex` to track the current position. A `watch` on the `state` automatically pushes new changes to the history. `undo` and `redo` functions navigate this history, updating the `state` to previous or future versions. `canUndo` and `canRedo` computed properties provide checks for button disabling, making the composable highly reusable for various data types (objects, primitives, arrays) and user interfaces.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs