Back to React Spring

useChain

docs/app/routes/docs.components.use-chain.mdx

10.0.33.7 KB
Original Source

import { formatFrontmatterToRemixMeta } from '../helpers/meta'

export const meta = formatFrontmatterToRemixMeta(frontmatter)

useChain

useChain is used to orchestrate animation hooks in sequence with one another. This is best used when you specifically want to orchestrate different types of animation hook e.g. useSpring & useTransition in sequence as opposed to multiple useSpring hooks where you could either use useSprings or create an async animation.

Usage

This will first run the useSpring hook and then the useTransition hook when the component has mounted and the useSpring has come to rest.

jsx
import {
  useTransition,
  useSpring,
  useChain,
  animated,
  useSpringRef,
} from '@react-spring/web'

const data = ['hi', 'there!']

function MyComponent() {
  const springRef = useSpringRef()
  const springs = useSpring({
    ref: springRef,
    from: { size: '20%' },
    to: { size: '50%' },
  })

  const transRef = useSpringRef()
  const transitions = useTransition(data, {
    ref: transRef,
    from: { scale: 0 },
    enter: { scale: 1 },
    leave: { scale: 0 },
  })

  useChain([springRef, transRef])

  return (
    <animated.div
      style={{
        height: springs.size,
        width: springs.size,
        background: 'blue',
      }}
    >
      {transitions((style, item) => (
        <animated.div
          style={{
            width: '120px',
            height: '120px',
            background: 'green',
            ...style,
          }}
        >
          {item}
        </animated.div>
      ))}
    </animated.div>
  )
}

Timesteps Explained

Using the previous as an example we can see that the transition is ran after the useSpring hook has come to rest. This is the default behaviour of the useChain hook.

However, they may be some instances where you want to define how long before the next spring is triggered. That's where timesteps come in.

Take this usage of useChain:

jsx
useChain([springRef, transRef], [0, 1], 1000)

We've added two additional arguments to the hooks, the first is a number array of timesteps (numbers must be in the range 0-1) that should model to the index of your SpringRefs and the second is a the timeframe (defaulting to 1000ms).

The way to think about the timesteps & timeframe is that the timestep of the hooks, multiplied by the timeframe is the delay you apply to your animations:

jsx
const refs = [springRef, transRef]
const timesteps = [0, 1]
const timeframe = 1000

refs.forEach((ref, index) => {
  /**
   * for the first ref this would be 0 because 0 * 1000 = 0
   * for the second ref this would be 1000 because 1 * 1000 = 1000
   */
  const time = timesteps[index] * timeframe

  // the delay is then applied to the animation.
  ref.delay = time
})

So therefore if you wanted your transition to come in after 400ms you could do this:

tsx
useChain([springRef, transRef], [0, 0.4])

Note, we omitted the timeframe argument here because it has a default of 1000.

Reference

This hook does not have a configuration object or take additional props.

Typescript

tsx
function useChain(refs: ReadonlyArray<SpringRef>): void

function useChain(refs: ReadonlyArray<SpringRef>, timeSteps: number[]): void

function useChain(
  refs: ReadonlyArray<SpringRef>,
  timeSteps: number[],
  timeFrame: number
): void

Examples

import { ExampleGrid } from '../components/Grids/ExampleGrid'

<ExampleGrid sandboxTitles={['Chaining Transition and a Spring', 'Smile Grid']} />

Can't find what you're looking for? Check out all our examples!