简体   繁体   English

如何使用 React Material UI 的过渡组件动画将项目添加到列表?

[英]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额外资源

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要点是你

  1. wrap all of the components you want to transition in the <TransitionGroup> component<TransitionGroup>组件中包装你想要过渡的所有组件
  2. Inside the TransitionGroup , put in the "condition" (logic or loop output) for the data you want to renderTransitionGroup中,为要渲染的数据输入“条件”(逻辑或循环输出)
  3. Wrap the individual components you want to transition with transition component of your choice - <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.通过这个设置,我发现我不需要在TransitionGroupCollapse上放置任何道具,并且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我通过以下方式更改了沙箱

  • Included TransitionGroup from react-transition-group包含来自react-transition-group TransitionGroup
  • Changed the "add" logic so that the components aren't part of the "items" array - the array only contains the data required to render the components更改了“添加”逻辑,以便组件不属于“项目”数组 - 该数组仅包含渲染组件所需的数据
  • I have added a simple "count" and pushed that to the array to give the items a unique index (had originally used 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 的数据库。
  • Rendered the components in a loop based on the data in the array (this could be done in a separate function, but the gist is that the components aren't being stored in the array)根据数组中的数据在循环中渲染组件(这可以在单独的 function 中完成,但要点是组件没有存储在数组中)
  • added a "delete" function to show the removal of single items添加了“删除” function 以显示单个项目的删除
  • wrapped the whole group in a second <TransitionGroup> to show that the unmounting can happen in a group level将整个组包裹在第二个<TransitionGroup>中,以表明卸载可以发生在组级别
  • Put in some simple styling to get a better idea of the effect.放入一些简单的样式以更好地了解效果。 You could use Material UI components here, but just wanted to keep it simple.您可以在这里使用 Material UI 组件,但只是想保持简单。

Hope this helps someone in the future.希望这对将来的某人有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将Material-UI的快餐栏和输入组件结合在一起进行反应? - How to combine Material-UI's snackbar and input components in react? 如何在React JS中的材料UI中的列表项上设置点击监听器 - How to set click listener on list item in material ui in react js 如何显示通过Material UI React选择了菜单列表中的哪个项目? - How do I show which item in the Menu List is selected with Material UI React? 如何使用 React 和 Material UI 访问列表中所选项目的索引? - How do I access the index of a selected item in list using React and Material UI? 使用jquery,如何动画添加新的列表项到列表? - Using jquery, how to I animate adding a new list item to a list? 如何在 Vue 的 Transition 和 TransitionGroup 组件中使用 animate.css 动画 - How to use animate.css animations with Vue's Transition and TransitionGroup components 反应材料 Ui 工具提示与列表项 - React material Ui tooltip with list item 如何覆盖材质 UI 组件中的自动完成选择选项 - How can I override autocomplete selected option in material UI components 对于 Material UI,我如何知道每个组件的属性是什么? - For Material UI, how can I know what the properties of each components are? 如何将 react-draggable 与 material-ui 动画与 react-transition 组一起使用 - How to use react-draggable with material-ui animations with react-transition group
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM