use-previous
Track the value a reactive source held before its latest change.
| Package | @vizejs/composable/use-previous |
| Own the source | vize lib pull composable:use-previous |
| Runtime exports | usePrevious |
| Gzip budget | 1024 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { usePrevious } from "@vizejs/composable/use-previous";
Try it
Show how a ticket price moved
Compare a value with the one it replaced to describe a change, without keeping your own history.
What to observe: Before any edit there is no earlier price. Change 120 to 150 to see Up 30 from 120, then to 90 to see Down 60 from 150. Entering the same price again reports it as unchanged.
usePrevious returns a readonly ref that holds the value the source had before its last change, starting as undefined unless you pass an initial value. It updates synchronously, so the comparison is ready in the same render.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { computed, ref } from "vue";
import { usePrevious } from "@vizejs/composable/use-previous";
const price = ref(120);
const previous = usePrevious(price);
const change = computed(() => {
if (previous.value === undefined) return "No earlier price yet.";
const delta = price.value - previous.value;
if (delta === 0) return `Unchanged from ${previous.value}.`;
return `${delta > 0 ? "Up" : "Down"} ${Math.abs(delta)} from ${previous.value}.`;
});
</script>
<template>
<div class="composable-example">
<p>Show how a ticket price moved since the last change.</p>
<label>
Ticket price
<input v-model.number="price" type="number" min="0" step="10" />
</label>
<output aria-live="polite">{{ change }}</output>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
usePrevious |
state | experimental | safe | stable | none | web, server, worker, native, desktop, terminal | — | — |
API
usePrevious
Track the value a reactive source held before its latest change. The semantics are precise and arity-based: - Without an initial argument the ref holds undefined until the source changes for the first time. - With an initial argument (including an explicit undefined when Value allows it) the ref holds that value until the first change, and the return type never widens with undefined. - Every synchronous write is observed (flush: "sync"), so a sequence of writes in one tick shifts the previous value step by step instead of collapsing into one batch. - Writes whose value is Object.is-equal to the current value do not count as changes, matching Vue's own change detection. - Tracking is shallow: reassignments are observed, in-place mutations of object values are not. Safe during server rendering: no browser globals are read and no timers start. The underlying watcher is bound to the current reactive scope and stops with it; call inside an active scope, or the watcher lives as long as the source. A plain non-reactive source never changes, so the ref stays at its initial value.
function usePrevious<Value>( source: MaybeRefOrGetter<Value>, ): Readonly<ShallowRef<Value | undefined>>
const route = shallowRef("/home");
const previousRoute = usePrevious(route, "/");
route.value = "/settings";
previousRoute.value; // "/home"
usePrevious
function usePrevious<Value>( source: MaybeRefOrGetter<Value>, initial: Value, ): Readonly<ShallowRef<Value>>
usePrevious
function usePrevious<Value>( source: MaybeRefOrGetter<Value>, ...initial: readonly [] | readonly [Value] ): Readonly<ShallowRef<Value | undefined>>