← Back to all hooks

usePrevious

Track the previous value of state or props. Essential for comparing current vs previous values in animations, transitions, and change detection.

Live Demo

See how usePrevious tracks the previous value across different types of state.

🔢 Counter Example

Current: 0
Previous: undefined

✏️ Text Input Example

Current: (empty)
Previous: (empty)

🎨 Color Picker Example

Current Color
#667eea
Previous Color
undefined

💡 How It Works:

  • Returns the value from the previous render
  • First render returns undefined (no previous value)
  • Perfect for comparing current vs previous state/props
  • Useful for animations, transitions, and change detection

Code Examples

Basic Usage

import { usePrevious } from "@uiblock/hooks";
import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  const previousCount = usePrevious(count);

  return (
    <div>
      <p>Current: {count}</p>
      <p>Previous: {previousCount ?? 'undefined'}</p>
      <p>Change: {previousCount !== undefined ? count - previousCount : 'N/A'}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

Detecting Direction of Change

import { usePrevious } from "@uiblock/hooks";
import { useState } from "react";

export default function ScrollDirection() {
  const [scrollY, setScrollY] = useState(0);
  const previousScrollY = usePrevious(scrollY);

  useEffect(() => {
    const handleScroll = () => setScrollY(window.scrollY);
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const direction = previousScrollY !== undefined
    ? scrollY > previousScrollY ? '⬇️ Down' : '⬆️ Up'
    : '—';

  return <div>Scroll Direction: {direction}</div>;
}

Animating Value Changes

import { usePrevious } from "@uiblock/hooks";
import { useState, useEffect } from "react";

export default function AnimatedNumber() {
  const [value, setValue] = useState(0);
  const previousValue = usePrevious(value);
  const [isAnimating, setIsAnimating] = useState(false);

  useEffect(() => {
    if (previousValue !== undefined && previousValue !== value) {
      setIsAnimating(true);
      const timer = setTimeout(() => setIsAnimating(false), 300);
      return () => clearTimeout(timer);
    }
  }, [value, previousValue]);

  return (
    <div
      style={{
        transform: isAnimating ? 'scale(1.2)' : 'scale(1)',
        transition: 'transform 0.3s',
        color: value > (previousValue ?? 0) ? 'green' : 'red'
      }}
    >
      {value}
    </div>
  );
}

Comparing Props Changes

import { usePrevious } from "@uiblock/hooks";
import { useEffect } from "react";

interface Props {
  userId: string;
}

export default function UserProfile({ userId }: Props) {
  const previousUserId = usePrevious(userId);

  useEffect(() => {
    if (previousUserId && previousUserId !== userId) {
      console.log(`User changed from ${previousUserId} to ${userId}`);
      // Fetch new user data, show transition, etc.
    }
  }, [userId, previousUserId]);

  return <div>User ID: {userId}</div>;
}

How It Works

Here's the implementation:

import { useRef, useEffect } from 'react'

export function usePrevious<T>(value: T): T | undefined {
  const ref = useRef<T>()

  useEffect(() => {
    ref.current = value
  }, [value])

  return ref.current
}

Key Features:

  • Uses useRef to store value without causing re-renders
  • Updates ref in useEffect after render completes
  • Returns undefined on first render (no previous value)
  • Works with any type: primitives, objects, arrays

API Reference

Parameters

value: T

The current value to track

Returns

T | undefined - The value from the previous render, or undefined on first render

💡 Use Cases

  • Detecting direction of change (up/down, increase/decrease)
  • Animating transitions between values
  • Comparing current vs previous props in components
  • Tracking scroll direction
  • Form field change detection
  • Undo/redo functionality
  • Analytics and change tracking
  • Conditional effects based on value changes