I have simple react app that contains 3 components: app, ul and li. The app holds an array of items.
Every 5 seconds (with set interval) the app slices 3 consecutive items and send them to the ul component to be displayed. If we start with:
item 3
item 2
item 1
after 5 seconds the list will be:
item 4
item 3
item 2
I'm trying to create an animation that once the props to the ul are updated, will push down the current list, until the bottom item is hidden, and after that it the next item should appear on top.
I thought about using the getDerivedStateFromProps method to activate the animation, use async await to hold the app until the animation will end (translateY) and then apply another animation of opacity on the new item.
I don't think it's a good solution and I think there must be simpler way to do it.
I also tried using the react transition group, but it only works when the item appear and not when content is changing.
I would love if anyone could point me in the right direction.
There are a ton of options to animate this type of event in React.
It's usually referred to as a Transition, because you need to animate a component before it unmounts. You can either:
Implement it yourself:
By using state in the <ul> component. Your ul should keep track
of every item it has rendered in its state and only remove an item
from the list when that item has called a callback at the end of its
animation.
Make your li components be able to receive a shouldGoAway prop as
a boolean and an animationCallback that will be called when the
animation is over. The li should check if prop.shouldGoAway and if
it is true is should animate itself to fall out of view (use a react
animation library like react-spring, a js animation library
like animejs or pure CSS animations) and call the
animationCallback when it is done.
Use one of the many React animation libraries that support Transition animations.
The choices that come to mind are react-transition-group, react-spring and react-motion.
Good luck.
Related
I'm rendering a number of items, where each individual item uses the same component:
This component internally uses Suspense:
<Suspense fallback={<Spinner />}>{children}</Suspense>
Whenever I click the paginator, a new set of items is rendered. Each of the items uses the same "Suspensed" component.
Problem: Each of the instances shows a fallback (spinner, loader) for a moment, and only then its content.
Since the fallback has constant height, this changes the height of the parent container, which makes the whole page jumping around:
I'm wondering how could I fix this? Basically, I'd like to avoid the new set of items to collapse due to showing the fallback. Sure, showing the fallback on initial load is fine, but I don't think the already loaded component (dynamically imported code) should show it on consequent pages.
I tried using React.startTransition, but that didn't help.
I also checked with components which are not lazily loaded, and everything works fine (parent height remains constant).
Thanks for help!
Update: I came up with a "poor man's fix":
wrapping children inside 2 divs
ResizeObserver monitoring the height of the inner div and setting the same height to the outer one, but in debounced fashion (100ms later)
Resources:
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver
https://www.npmjs.com/package/use-debounce
Note: You'll probably need to mock ResizeObserver in your Jest tests: https://github.com/que-etc/resize-observer-polyfill/issues/50#issuecomment-488064120
I am building a task manager with React and Framer Motion. I'm animating a slide in transition for a react Portal / modal. The portal has a form in it with multiple input text fields in it, each with their own onChange handlers. However, whenever the onChange handler is called, the animation replays itself. I'm not sure what is the issue.
I've tried to add a repeat value of 0 to the transitions, but there seems to be no change. I'm pretty new to framer motion, so please let me what other details I need to provide.
If you are using animate prop, the component will animate on each render, this is useful only for simple cases, where the component typically renders once on the page. But in your case, this prop will not work since the input field re-renders on each change.
For your use case, it's better to use useAnimation() hook and pass the animationControl as variant prop and fire it manually on the first render only.
useEffect(() => {
if (firstRender) {
animationControl.start();
}
}, [])
I'm looking to use the React Transition Group library to animate some stuff in my React page. According to those docs, the TransitionGroup component does the following:
The <TransitionGroup> component manages a set of transition components
( and <CSSTransition>) in a list. Like with the transition
components, <TransitionGroup> is a state machine for managing the
mounting and unmounting of components over time.
Consider the example below. As items are removed or added to the
TodoList the in prop is toggled automatically by the
<TransitionGroup>.
I'm not really sure what that means or why it's important.
Also, when I modify the example code that they embed on the documentation page so that the <TransitionGroup> tags are replaced with <ul> tags everything seems to work just fine (I can remove todo items by clicking on them, I can add new todo items).
Why is <TransitionGroup> component necessary? What does it do? (And why do things appear to work just fine when I replace it with an unordered list?)
React Transition Group has some advantages over typical css animations.These are some points that are coming to my mind.
Its uses binding to change classes for a components. eg: enter, appear, enter-active, appear-active, exit, exit-active etc are all part of animation classes. This make it really interactive interms of rich animations which you can not achive otherwise.
It has advatage to unmount your component using javascript, once animation is done. So basically no extra load on your front end.
It gives your freedom to define animations which ever way you like. Either css classes or defineing your own styles with in js file.
It gives you various type of animation options. Eg: Switch Transitions, Transition Groups, CssTransitions etc.
I would suggest to keep experimenting with typical css animations and react transition group and come to your own conclusion.
I'm using the react-slick library to make a slider, and I would like to change active slides and the slide which is at the top of the slider. For example, if I click on a button in the current page, I want the current slide at the top of the slider to change.
Do you know if is it possible to do this properly with this library?
I found a solution on the react-slick github (https://github.com/akiran/react-slick/issues/738), which consists of creating a ref to the slideshow and setting the focus via this.slider.innerSlider.list.focus(). However, this does not work very well, because the element I want is not at the very top of the slider. For example, if I set the focus on the second to last slide, the first element of my list is not accessible any more via the arrows.
If this.slider is a ref to your Slick component, you can force the slideshow to show a slide by calling the method slickGoTo() with the index of the desired slide. For example, to show the second slide:
this.slider.current.slickGoTo(1);
For details on the methods that you can call using your ref, see: react-slick API: Methods.
I have a basic plunker which shows the problem: http://plnkr.co/edit/L3rhEIdrnTucG0M7yGhO?p=preview. When you click on the button the first element is shown/hidden with a bouncy animation. This works fine, but the problem is that the items below it just jump to the new place which is quite ugly and jarring.
So, if you click on the button, item One slides away and then a second later items Two and Three jump up. I'd like everything to slide up while item One slides away. How can this be done? Do I need to drop animate.css and write my own custom animations? How would that work? (I don't really care about the bouncy animation, it should just slide away / back into view.)
The current bouncy animation that you have is using a transform property which isn't going to effect sibling elements. If you did something like animate the margin, other elements would move as well.
You could either change the animation method on your target element, or leave it and additionally animate the target's adjacent sibling. I modified your Plunker demonstrating the latter:
http://plnkr.co/edit/hMaPgRDYC8Z0EeCs6SHQ?p=preview
*This also demonstrations using transitions on the hide and keyframes on the show.
To select the adjacent sibling next to the one being effected by ng-hide, make a css selector with the + symbol:
.item.ng-hide-add + .item {...}
Then by transitioning/animating margin-top, the remaining item elements will get pushed around too.