[英]How can I use React Material UI's transition components to animate adding an item to a list?
I have this class.我有这个 class。
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
items: []
};
this.add = this.add.bind(this);
this.clear = this.clear.bind(this);
}
add() {
this.setState(prev => {
const n = prev.items.length;
return {
items: [<li key={n}>Hello, World {n}!</li>, ...prev.items]
};
});
}
clear() {
this.setState({ items: [] });
}
render() {
return (
<div>
<div>
<button onClick={this.add}>Add</button>
<button onClick={this.clear}>Clear</button>
</div>
{/* This is wrong, not sure what to do though... */}
<Collapse in={this.state.items.length > 0}>
<ul>{this.state.items}</ul>
</Collapse>
</div>
);
}
}
Sandbox link: https://codesandbox.io/s/material-demo-ggv04?file=/Demo.js沙盒链接: https://codesandbox.io/s/material-demo-ggv04?file=/Demo.js
I'm trying to make it so that every time I click the "add" button, a new item gets animated into existence at the top of the list and the existing items get pushed down.我正在努力做到这一点,以便每次单击“添加”按钮时,一个新项目会在列表顶部以动画方式存在,并且现有项目会被下推。 Not sure how to proceed though.不知道如何进行。
Extra Resources额外资源
Collapse
) React 过渡组过渡文档: http://reactcommunity.org/react-transition-group/transition (似乎由Collapse
在内部使用)I updated your Sandbox code to achieve what you wanted, but I don't think MaterialUI is the best library for that (I could be missing a better way to do it).我更新了你的沙盒代码来实现你想要的,但我不认为 MaterialUI 是最好的库(我可能会错过更好的方法)。
The challenge is that when you add a new item, that doesn't exist in the DOM yet.挑战在于,当您添加新项目时,DOM 中尚不存在该项目。 And most of those animation libraries/components require the element to be in the DOM and they just "hide" and "show" it with a transition time.并且大多数 animation 库/组件要求元素位于 DOM 中,它们只是“隐藏”和“显示”它并带有过渡时间。
I had a similar situation and after some research, the better library I found that can handle animation for elements that are not yet in the DOM, was the Framer Motion .我遇到了类似的情况,经过一些研究,我发现可以处理 animation 的更好的库是Framer Motion 。 (You can check their documentation for mount animations ) (您可以查看他们的 安装动画文档)
Anyway, here is the link for the new Code Sandbox so you can take a look.无论如何,这里是新代码沙箱的链接,所以你可以看看。 The changes I made:我所做的更改:
Removed random key删除了随机密钥
In the map
function that creates your list using the <Collapse />
component, there was a function to get a random integer and assign that as a key
to your component. In the map
function that creates your list using the <Collapse />
component, there was a function to get a random integer and assign that as a key
to your component. React needs to have consistent keys to properly do its pretenders, so removing that random number fixes the issue where your "Toggle" button wasn't animating properly. React 需要有一致的键才能正确地进行伪装,因此删除该随机数可以解决您的“切换”按钮没有正确动画的问题。 (If your list of items doesn't have an unique ID, just use the index of the map
function, which is not a good solution, but still better than random numbers). (如果您的项目列表没有唯一 ID,只需使用map
function 的索引,这不是一个好的解决方案,但仍然比随机数好)。
<Collapse key={i} timeout={this.state.collapseTimeout} in={this.state.open}>
{it}
</Collapse>
Added a new function to control the toggle添加了一个新的 function 来控制切换
The approach here was: add the item in your list and, after the element is in the DOM, close the <Collapse />
, wait a little bit and open it again (so you can visually see the animation).这里的方法是:在列表中添加项目,在元素进入 DOM 后,关闭<Collapse />
,稍等片刻,然后再次打开它(这样你就可以直观地看到动画)。 In order to do that, we needed a new "toggle" function that can explicit set the value of the collapse.为了做到这一点,我们需要一个新的“切换” function 可以显式设置折叠的值。
toggleValue(value) {
this.setState(() => {
return {
open: value
};
});
}
Added a variable timeout for the collapse为崩溃添加了可变超时
The last issue was that, closing the <Collapse />
when the new item is added, was triggering the animation to close it.最后一个问题是,在添加新项目时关闭<Collapse />
会触发 animation 将其关闭。 The solution here was to dynamically change the timeout of the collapse, so you don't see that.这里的解决方案是动态改变崩溃的超时时间,所以你看不到。
setCollapseTimeout(value) {
this.setState(() => {
return {
collapseTimeout: value
};
});
}
When adding the element to the list, wait to trigger the animation Again, to work around the issue with elements not yet in the DOM, we need to use a setTimeout
or something to wait to toggle the <Collapse />
.将元素添加到列表时,等待触发 animation同样,要解决尚未在 DOM 中的元素的问题,我们需要使用setTimeout
或其他东西来等待切换<Collapse />
。 That was added in your add()
function.这是在您的add()
function 中添加的。
add() {
this.toggleValue(false);
this.setCollapseTimeout(0);
this.setState(prev => {
const n = prev.items.length;
return {
items: [<li key={n}>Hello, World {n}!</li>, ...prev.items]
};
});
setTimeout(() => {
this.setCollapseTimeout(300);
this.toggleValue(true);
}, 100);
}
Again, this is a hacky solution to make <Collapse />
from MaterialUI work with elements that are not yet in the DOM.同样,这是一个让 MaterialUI 中的<Collapse />
与尚未在 DOM 中的元素一起工作的 hacky 解决方案。 But, as mentioned, there are other libraries better for that.但是,如前所述,还有其他更好的库。
Good luck:)祝你好运:)
Ended up here earlier on and then came back to create a sandbox showing hopefully a simple method for this scenario.早些时候在这里结束,然后回来创建一个沙箱,希望能展示一种适用于这种情况的简单方法。 The material-ui
docs are a bit (lot) light in this area and I was fighting with a very similar situation, but I tried something with TransitionGroup
from react-transition-group
, crossed my fingers and it seemed to work. material-ui
文档在这方面有点(很多)轻松,我正在与非常相似的情况作斗争,但我尝试了react-transition-group
中的TransitionGroup
,交叉手指,它似乎有效。
Forked CodeSandbox with TransitionGroup 带有 TransitionGroup 的分叉 CodeSandbox
The gist is that you要点是你
<TransitionGroup>
component在<TransitionGroup>
组件中包装你想要过渡的所有组件TransitionGroup
, put in the "condition" (logic or loop output) for the data you want to render在TransitionGroup
中,为要渲染的数据输入“条件”(逻辑或循环输出)<Collapse>
in this example用您选择的过渡组件包裹您要过渡的各个组件 - 在本例中为<Collapse>
eg In its most simple setup where "items" is an array of unique numbers coming from either props, state or a redux store例如,在其最简单的设置中,“项目”是来自任一道具的唯一数字数组,state 或 redux 商店
<TransitionGroup>
{items.map(item => (
<Collapse key={item}>
I am item {item}
</Collapse>
))}
</TransitionGroup>
With this setup I have found that I didn't need to put any props on the TransitionGroup
or Collapse
, and the TransitionGroup
handled all the mounting and unmounting in the loop rendering.通过这个设置,我发现我不需要在TransitionGroup
或Collapse
上放置任何道具,并且TransitionGroup
处理了循环渲染中的所有安装和卸载。 Material UI doesn't produce the lightest of HTML output, but I guess it's all rendered on the fly so maybe that makes it better (unless you have thousands of elements, then things start to drag). Material UI 不会产生最轻的 HTML output,但我想这一切都是即时渲染的,所以也许这会让它变得更好(除非你有数千个元素,然后事情开始拖累)。
You can even go a step further and wrap the whole thing in another TransitionGroup
to cover situations where you want to remove the whole thing without transitioning all of the individual items - in this instance I switched it to a <Slide>
.您甚至可以进一步 go 并将整个事物包装在另一个TransitionGroup
中,以涵盖您想要删除整个事物而不转换所有单个项目的情况 - 在这种情况下,我将其切换为<Slide>
。 I was absolutely certain that this wouldn't work, but it seemed to not care.我绝对确定这行不通,但它似乎不在乎。 You can also try and be semantic and use the "component" property rather than wrapping in another element eg您也可以尝试语义化并使用“组件”属性,而不是包装在另一个元素中,例如
<TransitionGroup>
{items.length > 0 && (
<Slide>
<TransitionGroup component="ul">
{items.map((item) => (
<Collapse component="li" key={item}>I am item {item}</Collapse>
))}
</TransitionGroup>
</Slide>
)}
</TransitionGroup>
I have changed the sandbox in the following ways我通过以下方式更改了沙箱
TransitionGroup
from react-transition-group
包含来自react-transition-group
TransitionGroup
Math.random
, but I wanted a "prettier" output).我添加了一个简单的“计数”并将其推送到数组中,以便为项目提供唯一索引(最初使用的是Math.random
,但我想要一个“更漂亮”的输出)。 Generally your items will probably be coming from a database somewhere where a unique id will already be set.通常,您的项目可能来自已设置唯一 ID 的数据库。<TransitionGroup>
to show that the unmounting can happen in a group level将整个组包裹在第二个<TransitionGroup>
中,以表明卸载可以发生在组级别Hope this helps someone in the future.希望这对将来的某人有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.