react-spring icon indicating copy to clipboard operation
react-spring copied to clipboard

[feat]: Animate Presence component addition

Open joshuaellis opened this issue 2 years ago • 6 comments

A clear and concise description of what the feature is

A new component / hook that animates elements depending on whether their children are being rendered or not without the need to be passing data (this is similar but separate to useTransition which could be depreciated in favour of this new hook)

Why should this feature be included?

framer-motion has a component called animate presence which is fairly similar to our useTransition except with the latter, you have to pass state to the hook to control the appearance of the animated components.

This isn't the worst thing when you're only controlling one modal for instance, but if you want to control multiple it would be easier to be able to handle the animations depending on whether the dom element was mounted or not (see here for more context).

This feature would hopefully lead into #1628 which is also something I would be very interested in adding to react-spring.

Please provide an example for how this would work

Unlike framer-motion, rs has two parts, the hook that runs outside the react-render world & the animated component that interpolates those SpringValues to be applied to the DOM element.

We could create a new component in a similar API style to AnimatePresence, but it would be more inline with the direction of react-spring if we could make a hook & the an additional HOC built on animated to register these components for the hook to manipulate & track. So an ideal approach can be seen below:

const MyComponent = ({show}) => {
	const springs = useAnimatePresence({
		from: {
			opacity: 0,
		},
		enter: {
			opacity: 1
		},
		leave: {
			opacity: 0
		}
	}) 

	return show ? <animatedPresence.div style={springs}>Hello world</animatedPresence.div> : null
}

Of course, happy to hear other people's API design ideas // thoughts or even concerns about this feature.

joshuaellis avatar Aug 02 '22 07:08 joshuaellis

I really like that API, it feels distinctly react-spring.

In this hypothetical situation, would the springs object be passed to an animated.div? Would useAnimatePresence and animatedPresence.div exist in the same component or could animatedPresence.div wrap a component using the hook?

leo-petrucci avatar Aug 02 '22 08:08 leo-petrucci

In this hypothetical situation, would the springs object be passed to an animated.div

Yes sorry, i've updated it now!

Would useAnimatePresence and animatedPresence.div exist in the same component or could animatedPresence.div wrap a component using the hook

Are you able to give an example of what you're suggesting?

joshuaellis avatar Aug 02 '22 08:08 joshuaellis

Are you able to give an example of what you're suggesting?

My components won't always know they're being unmounted, ideally they should just know that when they are being mounted/unmounted certain animations should be played.

If animatedPresence.div is inside the component that is being unmounted, then it won't be aware that it's being unmounted and the animation won't play.

const Wrapper = ({show}) => (
  <>
  {
    show ? <MyComponent /> : null
  }
  </>
)

const MyComponent = () => {
	const springs = useAnimatePresence({
		from: {
			opacity: 0,
		},
		enter: {
			opacity: 1
		},
		leave: {
			opacity: 0
		}
	}) 

	return <animatedPresence.div style={springs}>Hello world</animatedPresence.div>
}

So I think something like this would make more sense?

const Wrapper = ({show}) => (
  // magic, knows when its children are mounted and unmounted
  <animatedPresence.div>
  {
    show ? <MyComponent /> : null
  }
  </animatedPresence.div>
)

const MyComponent = () => {
  // Will get information from `<animatedPresence.div>` above
	const springs = useAnimatePresence({
		from: {
			opacity: 0,
		},
		enter: {
			opacity: 1
		},
		leave: {
			opacity: 0
		}
	}) 

  // animations are applied to a standard `animated.div`
	return <animated.div style={springs}>Hello world</animated.div>
}

leo-petrucci avatar Aug 02 '22 09:08 leo-petrucci

Aha, I understand. Then maybe all animated components try to register themselves with the closest animatedprescence component!

And animtedpresence just wraps them 👌🏼

joshuaellis avatar Aug 02 '22 09:08 joshuaellis

Excited about this proposal! Animations not playing because of components not knowing they're unmounting is the biggest pain point when using react-spring.

This feature would also work really well with floating-ui's APIs and make the components easier to compose. Example with framer-motion's AnimatePresence here.

evangeline avatar Aug 08 '22 03:08 evangeline

Any news on this API?

marioparaschiv avatar Mar 13 '24 14:03 marioparaschiv