1

I'm working from this example, which is from the React Spring docs: https://codesandbox.io/s/github/pmndrs/react-spring/tree/master/demo/src/sandboxes/simple-transition?file=/src/App.tsx

My use-case is different because I need be able to go back and forth between components, and change the animation direction based on next component index. If the next panel index is greater than the current one, I want the current panel to exit left and the new panel to enter right. If the new index is less than, I want the reverse.

Here is my code:

import React, { CSSProperties } from 'react'
import {
  useTransition,
  animated,
  AnimatedProps,
  useSpringRef,
  config,
} from '@react-spring/web'


import { schemas } from 'types'

import BottomPanelContent from './BottomPanelContent'

interface Props {
  // the BottomPanelContent expects the contents of one of these as a prop
  panels: schemas['ModuleObjects']['TextWithRotatingBottomPanel']['config']['bottom_panels']
  // I have a parent component handling changing the state between the indexes
  currentPanelIdx: number
}

export default function Animator({ panels, currentPanelIdx }: Props) {
  const [prevPanelIdx, setPrevPanelIdx] = React.useState(-1)
  const [from, setFrom] = React.useState<string>('translateX(100%)')
  const [leave, setLeave] = React.useState<string>('translateX(-100%)')

  React.useEffect(() => {
    const isGoingForward = currentPanelIdx > prevPanelIdx
    setFrom(`translateX(${isGoingForward ? '100' : '-100'}%)`)
    setLeave(`translateX(${isGoingForward ? '-100' : '100'}%)`)
    setPrevPanelIdx(currentPanelIdx)
  }, [currentPanelIdx])

  const transRef = useSpringRef()
  const transitions = useTransition(currentPanelIdx, {
    ref: transRef,
    keys: null,
    initial: { transform: 'translateX(0%)' },
    from: { transform: from },
    enter: { transform: 'translateX(0%)' },
    leave: { transform: leave },
    exitBeforeEnter: true,
    delay: 0,
    config: config.default,
    trail: 0,
  })

  React.useEffect(() => {
    transRef.start()
  }, [prevPanelIdx])

  const panelElements: ((
    props: AnimatedProps<{ style: CSSProperties }>
  ) => React.ReactElement)[] = panels.map(p => ({ style }) => (
    <animated.div style={{ ...style, minWidth: '100%' }}>
      <BottomPanelContent {...p} />
    </animated.div>
  ))

  return (
    <div
      style={{
        position: 'absolute',
        width: '100%',
        height: '100%',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        willChange: 'transform',
      }}>
      {transitions((style, i) => {
        const Panel = panelElements[i]
        return <Panel style={style} />
      })}
    </div>
  )
}

This is not working properly. The panels always leave in whatever direction would have been correct for the transition when they entered. Ie if you go from 0 - 1 - 2 works, but 0 - 1 - 0 results in 1 exiting to the left, when it should have exited to the right. Here's a gif to show what is happening:

https://i.stack.imgur.com/k4fbc.jpg

I had hoped that waiting to call transRef.start() until prevPanelIdx changed would be enough to update the styles getting passed from transitions. However I might be approaching this incorrectly. Potentially I should be using the dependency array in the useTransition hook, or passing functions to from and leave instead of what Ii'm doing now, but the documentation both of these options seems spotty to me. I made some efforts in those directions but failed as well.

I'm considering making a PR to the react spring docs if I get this working, as it seems to me a trivial case that could really help their docs out.

I can look into adding a demo if that's helpful, it will be a bit of work so let me know in the comments if that's needed :)

Willow
  • 1,132
  • 5
  • 20

1 Answers1

0

I think the approach I took was not very good. I seem to have a better approach by tinkering with the sandbox from the documentation: you can see my updated sandbox here: https://codesandbox.io/s/exciting-archimedes-p5k8ox?file=/src/App.tsx

I still need to do more work to apply this to the code in my example, and will update this answer when I do that.

Willow
  • 1,132
  • 5
  • 20