What's a react.js-friendly way to animate a list-reordering?
I just released a module to tackle exactly this problem
https://github.com/joshwcomeau/react-flip-move
It does a few things differently than Magic Move / Shuffle:
- It uses the FLIP technique for hardware-accelerated 60FPS+ animations
- It offers options to "humanize" the shuffle by incrementally offsetting delay or duration
- It handles interruptions gracefully, no weird glitch effects
- Bunch of other neat stuff like start/finish callbacks
Check out the demos:
http://joshwcomeau.github.io/react-flip-move/examples/#/shuffle
Animate when items in a list change order with React?
In react-spring there is an example about it. But it is quite complicated, there is a lot happening. I created a simplified version from it.
You have an array of names. You define a y value based on the index. And you can move the elements with translate property. The position is set to absolute.
With one click you can shuffle the array. With another click you can remove elements. In react transition, you can define the entering and leaving animation. The leaving animation called when you remove an element.
import { render } from 'react-dom';
import React, { useState } from 'react';
import { useTransition, animated } from 'react-spring';
import shuffle from 'lodash/shuffle';
import './styles.css';
let data = [
{
name: 'Rare Wind'
},
{
name: 'Saint Petersburg'
},
{
name: 'Deep Blue'
},
{
name: 'Ripe Malinka'
},
{
name: 'Near Moon'
},
{
name: 'Wild Apple'
}
];
function App() {
const [rows, set] = useState(data);
let height = 20;
const transitions = useTransition(
rows.map((data, i) => ({ ...data, height, y: i * height })),
d => d.name,
{
from: { position: 'absolute', height: 20, opacity: 0 },
leave: { height: 0, opacity: 0 },
enter: ({ y, height }) => ({ y, height, opacity: 1 }),
update: ({ y, height }) => ({ y, height })
}
);
return (
<div class="list" style={{ height }}>
<button onClick={() => set(shuffle(rows))}>click</button>
<button onClick={() => set(rows.slice(1))}>remove first</button>
{transitions.map(({ item, props: { y, ...rest }, key }, index) => (
<animated.div
key={key}
class="card"
style={{
zIndex: data.length - index,
transform: y.interpolate(y => `translate3d(0,${y}px,0)`),
...rest
}}
>
<div class="cell">
<div class="details">{item.name}</div>
</div>
</animated.div>
))}
</div>
);
}
const rootElement = document.getElementById('root');
render(<App />, rootElement);
Here is the sandbox: https://codesandbox.io/s/animated-list-order-example-with-react-spring-teypu
Edit: I added add element as well, because it is a nicer example this way. :)
Update: This sandbox is from necrifede who updated my example to version 9.:
https://codesandbox.io/s/animated-list-order-example-with-react-spring-forked-nhwqk9?file=/src/index.js
How to animate reorder with React Native FlatList?
The flatlist is sorted in order of the array that you feed it through the data
prop. Whether you are using component-level state (i.e. this.state
) or redux to manage your state, you can reorder the array of elements and it should rerender in that order. For example, one implementation may be:
const checkedData = [...this.state.data].filter(item => item.checked === true);
const uncheckedData = [...this.state.data].filter(item => item.checked !== true);
const sortedData = checkData.concat(uncheckedData);
this.setState({ data: sortedData });
The javascript filter function should preserve original sort order of the subset.
To animate it, you can then look into LayoutAnimation
in react native. It will apply an animation type to every change in your view between renders.
How to specify the order of items in ReactCSSTransitionGroup?
The ReactCSSTransitionGroup just animates changes in DOM, it doesn't care about order. Your state changes from odd to even numbers, there is no moment when it contains sorted array with all the numbers. You can work around it by modifying state in different way, temporary saving old items for animation purposes, something like that:
switch: function() {
var newItems;
if (this.state.items[0] % 2 !== 1) {
newItems = [1, 3, 5];
}
else {
newItems = [2, 4];
}
this.setState({
items: newItems,
previousItems: this.state.items
}, function() {
this.setState({
previousItems: []
})
});
}
After that, you need to modify your render method:
render: function() {
var currentItems = this.state.items.concat(this.state.previousItems).sort();
var items = currentItems.map(function(item, i) {
return (
<div key={item}>
{item}
</div>
);
}.bind(this));
return (
<div>
<button onClick={this.switch}>Switch</button>
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={1000} transitionLeaveTimeout={1000}>
{items}
</ReactCSSTransitionGroup>
</div>
);
}
Here is an updated fiddle: http://jsfiddle.net/ny5La5ky/
drag to reorder and save state with reactjs
I have fixed it,
here is the working url to play with https://codesandbox.io/s/quizzical-colden-rm62y
You were correct in guessing that the problem was with the onSortEnd
function. Instead of swapping the newIndex and oldIndex position we just need to either bubble them up or down.
Here is a working code, it can be cleaned up a bit, but you got the idea :)
const onSortEnd = ({ oldIndex, newIndex }) => {
setUsers(prevState => {
const newItems = [...prevState];
if (oldIndex > newIndex) {
for (let i = oldIndex - 1; i >= newIndex; i--) {
newItems[i].order++;
newItems[oldIndex].order = newIndex;
}
} else if (oldIndex < newIndex) {
for (let i = oldIndex + 1; i <= newIndex; i++) {
newItems[i].order--;
newItems[oldIndex].order = newIndex;
}
}
return newItems.sort((a, b) => a.order - b.order);
});
};
Hope it helps. Happy coding :)
ReactJS component: fadeIn / fadeOut on mouse-enter / mouse-leave
Something like this?
http://plnkr.co/edit/5tLWNTtpsSWBUCgnKwQO?p=preview
I updated the state to have a hovered attribute and two mouse enter / leave methods to set the value which are bound the .range-picker-selection element in the render function
<div className="range-picker-selection" onMouseEnter={this.onMouseEnterHandler} onMouseLeave={this.onMouseLeaveHandler}>
onMouseEnterHandler: function () {
this.setState({
hovered: true
})
},
onMouseLeaveHandler: function () {
this.setState({
hovered: false
})
},
I also updated the render function to set the opacity to 0 or 1 accordingly for the elements.
style={{opacity: this.state.hovered ? 1 : 0}}
Finally, the actual animation is done with CSS animations
transition: opacity 1s;
I hope this helps
Related Topics
JavaScript How to Check User Agent for Mobile/Tablet
How to Check If Character Isn't Supported by the User's Browser in JavaScript
Make :Focus Change CSS of Another Class
Why Blocking Event Loop Does Not Block CSS Animation
Trigger Same CSS Animation on Every Click
Transitioning Affixed Navigation Bar - CSS
CSS JavaScript Style Sheet Disabled
Jquery Select a Div with a Certain Class, That Doesn't Have Another Class
Android Webview JavaScript from Assets
CSS in My JavaScript Widget Colliding with Target Page CSS
React Onclick Add Class to Clicked Element But Remove from the Others
How to Check If Text Is Truncated by CSS Using JavaScript
How to Include CSS Files from an MVC Partial Control
Change Image Onclick for a Set Amount of Time
Laravel 8 + Nginx - App.CSS and App.Js Resources from Public/ Not Loading - 404 Not Found