JAVASCRIPT
Building an Undo/Redo Feature in Vue 3 with `watch`
Implement a robust undo/redo functionality in your Vue 3 applications using the `watch` Composition API to track and manage state changes efficiently.
// UndoRedoEditor.vue
<template>
<div>
<textarea v-model="editorContent" rows="10" cols="50"></textarea>
<div>
<button @click="undo" :disabled="!canUndo">Undo</button>
<button @click="redo" :disabled="!canRedo">Redo</button>
</div>
<p>Current Content: {{ editorContent }}</p>
<p>History Length: {{ history.length }}</p>
<p>Current Index: {{ historyIndex }}</p>
</div>
</template>
<script setup>
import { ref, watch, computed } from 'vue';
const editorContent = ref('Initial content');
const history = ref([]);
const historyIndex = ref(-1);
// Initialize history with the initial content
history.value.push(editorContent.value);
historyIndex.value = 0;
watch(editorContent, (newValue, oldValue) => {
// If we're not at the end of history (e.g., after an undo),
// trim future states before adding new one
if (historyIndex.value < history.value.length - 1) {
history.value = history.value.slice(0, historyIndex.value + 1);
}
history.value.push(newValue);
historyIndex.value = history.value.length - 1;
}, { deep: true, immediate: false }); // immediate: false to avoid adding initial state twice
const canUndo = computed(() => historyIndex.value > 0);
const canRedo = computed(() => historyIndex.value < history.value.length - 1);
const undo = () => {
if (canUndo.value) {
historyIndex.value--;
editorContent.value = history.value[historyIndex.value];
}
};
const redo = () => {
if (canRedo.value) {
historyIndex.value++;
editorContent.value = history.value[historyIndex.value];
}
};
</script>
How it works: This snippet demonstrates how to create a basic undo/redo functionality for a text editor using Vue 3's `watch` API. It maintains a `history` array of content states and a `historyIndex`. When `editorContent` changes, `watch` pushes the new state onto the history, pruning future states if an undo has occurred. `undo` and `redo` functions then navigate through this history, updating `editorContent` and disabling buttons as appropriate.