Skip to main content
Version: Next

useValue

The useValue hook is the core of React UI Animate. It creates animated values that update smoothly without causing React re-renders, making your animations performant and your code simple.

Understanding useValue

Think of useValue as useState optimized for animations. It returns a tuple [value, setValue] that you can use just like useState, but with superpowers:

  • No re-renders - Updates happen outside React's render cycle
  • Smooth animations - Works seamlessly with animation modifiers
  • Flexible types - Supports numbers, strings, arrays, and objects
  • Direct style binding - Use values directly in JSX styles

Basic Usage

The simplest way to use useValue is with a number:

import { useValue, animate } from 'react-ui-animate';

function MyComponent() {
const [width, setWidth] = useValue(100);

return (
<animate.div style={{ width, height: 100, background: 'teal' }} />
);
}

Immediate vs. Animated Updates

Understanding when values change instantly vs. smoothly is crucial:

Important
  • Raw values → Change immediately (no animation)
  • Modifier-wrapped values → Animate smoothly
const [width, setWidth] = useValue(100);

// ❌ Immediate change (no animation)
setWidth(200);

// ✅ Smooth animation
setWidth(withSpring(200));
setWidth(withTiming(200, { duration: 300 }));
import React from 'react';
import { animate, useValue, withSpring } from 'react-ui-animate';
import './styles.css';

export default function App() {
  const [width, setWidth] = useValue(100);

  return (
    <div className="container">
      <button
        className="button buttonPrimary"
        onClick={() => setWidth(withSpring(200))}
      >
        Expand
      </button>
      <button
        className="button buttonSecondary"
        onClick={() => setWidth(withSpring(100))}
      >
        Reset
      </button>
      <animate.div
        style={{
          width,
          height: 100,
          backgroundColor: 'teal',
          borderRadius: '8px',
          margin: '20px auto 0',
        }}
      />
    </div>
  );
}

Try it yourself: Click "Animate" to see a smooth spring animation, then "Reset" to see a timing-based transition back.

Supported Value Types

useValue works with multiple data types. Here's how to use each:

1. Primitive Values (Number & String)

Perfect for animating single properties like width, opacity, or color.

const [width, setWidth] = useValue(100);        // number
const [color, setColor] = useValue('teal'); // string

Real-world example: Animate a button's width on hover:

function ExpandableButton() {
const [width, setWidth] = useValue(100);

return (
<animate.button
onMouseEnter={() => setWidth(withSpring(200))}
onMouseLeave={() => setWidth(withSpring(100))}
style={{ width, padding: '10px 20px' }}
>
Hover me
</animate.button>
);
}
View full example
import React from 'react';
import { animate, useValue, withSpring } from 'react-ui-animate';
import './styles.css';

export default function App() {
  const [width, setWidth] = useValue(100);

  return (
    <div className="container">
      <button
        className="button buttonPrimary"
        onClick={() => setWidth(withSpring(200))}
      >
        Expand
      </button>
      <button
        className="button buttonSecondary"
        onClick={() => setWidth(withSpring(100))}
      >
        Reset
      </button>
      <animate.div
        style={{
          width,
          height: 100,
          backgroundColor: 'teal',
          borderRadius: '8px',
          margin: '20px auto 0',
        }}
      />
    </div>
  );
}

2. Arrays

Animate multiple values simultaneously. Perfect for lists, grids, or any collection of elements.

const [positions, setPositions] = useValue([0, 0, 0]);

Real-world example: Stagger animation for a list of items:

function AnimatedList() {
const [heights, setHeights] = useValue([0, 0, 0, 0]);

const expand = () => {
setHeights(withSpring([100, 100, 100, 100]));
};

return (
<>
<button onClick={expand}>Expand All</button>
{heights.map((height, i) => (
<animate.div
key={i}
style={{ height, background: 'teal', margin: 5 }}
/>
))}
</>
);
}
View full example
import React from 'react';
import { useValue, withSpring, animate } from 'react-ui-animate';
import '../../styles.css';

export default function App() {
  const [values, setValues] = useValue([0, 0, 0]);

  return (
    <div className="container">
      <button
        className="button buttonPrimary"
        onClick={() => setValues(withSpring([10, 100, 200]))}
      >
        Start
      </button>
      <button
        className="button buttonSecondary"
        onClick={() => setValues([0, 0, 0])}
      >
        Reset
      </button>

      <div style={{ marginTop: 20, display: 'flex', gap: 10, justifyContent: 'center' }}>
        {values.map((value, index) => (
          <animate.div
            key={index}
            style={{
              width: 100,
              height: 100,
              backgroundColor: 'teal',
              translateX: value,
              borderRadius: 8,
            }}
          />
        ))}
      </div>
    </div>
  );
}

3. Objects

Animate multiple properties together. Ideal for position, size, or any grouped properties.

const [position, setPosition] = useValue({ x: 0, y: 0 });
const [size, setSize] = useValue({ width: 100, height: 100 });

Real-world example: Animate a card's position and size together:

function AnimatedCard() {
const [style, setStyle] = useValue({
x: 0,
y: 0,
width: 200,
height: 200,
});

const moveAndResize = () => {
setStyle(
withSpring({
x: 100,
y: 100,
width: 300,
height: 300,
})
);
};

return (
<>
<button onClick={moveAndResize}>Move & Resize</button>
<animate.div
style={{
translateX: style.x,
translateY: style.y,
width: style.width,
height: style.height,
background: 'teal',
}}
/>
</>
);
}
View full example
import React from 'react';
import { useValue, withSpring, animate } from 'react-ui-animate';
import '../../styles.css';

export default function App() {
  const [obj, setObj] = useValue({ x: 0, y: 0, width: 100, height: 100 });

  return (
    <div className="container">
      <button
        className="button buttonPrimary"
        onClick={() =>
          setObj(
            withSpring(
              { x: 100, y: 100, width: 200, height: 200 },
              {
                onStart: () => console.log('START'),
                onComplete: () => console.log('Animation complete'),
              }
            )
          )
        }
      >
        Start
      </button>
      <button
        className="button buttonSecondary"
        onClick={() => setObj({ x: 0, y: 0, width: 100, height: 100 })}
      >
        Reset
      </button>

      <animate.div
        style={{
          width: obj.width,
          height: 100,
          backgroundColor: 'teal',
          margin: '20px auto 0',
          translateX: obj.x,
          translateY: obj.y,
          borderRadius: 8,
        }}
      />
    </div>
  );
}

Common Patterns

Pattern 1: Toggle Animation

function ToggleButton() {
const [isOpen, setIsOpen] = useState(false);
const [width, setWidth] = useValue(100);

useEffect(() => {
setWidth(withSpring(isOpen ? 200 : 100));
}, [isOpen]);

return (
<animate.button
onClick={() => setIsOpen(!isOpen)}
style={{ width }}
>
{isOpen ? 'Close' : 'Open'}
</animate.button>
);
}

Pattern 2: Conditional Animation

function ConditionalAnimation() {
const [isActive, setIsActive] = useState(false);
const [scale, setScale] = useValue(1);

useEffect(() => {
setScale(withSpring(isActive ? 1.2 : 1));
}, [isActive]);

return (
<animate.div
onClick={() => setIsActive(!isActive)}
style={{
scale,
width: 100,
height: 100,
background: isActive ? 'red' : 'teal',
}}
/>
);
}

Best Practices

✅ Do

  • Use useValue for values that change frequently (animations, gestures)
  • Combine related properties in objects for coordinated animations
  • Use animation modifiers (withSpring, withTiming) for smooth transitions
  • Access values directly in JSX (no need to call .value)

❌ Don't

  • Don't use useValue for static values (use useState instead)
  • Don't update values in render (causes issues)
  • Don't forget to use modifiers for animations (raw values change instantly)
  • Don't use useValue for complex state management (use state management libraries)

Performance Tips

  1. Batch updates - Update multiple properties in a single object rather than separate values
  2. Use appropriate modifiers - withSpring for natural motion, withTiming for precise control
  3. Avoid unnecessary re-renders - useValue already prevents re-renders, but don't trigger React state updates during animations

Next Steps

Now that you understand useValue, explore: