2

我正在使用 ReactCSSTransitionGroup 做一些动画,我发现了一件有趣的事情,对我来说没有任何意义。

在下面的示例中,当我单击 时<div className="HeartControl">,它将更新工作正常height的。<div className="HeartFill">(虽然我知道这里实现效果不一定需要 ReactCSSTransitionGroup)。

有趣的是,当我点击时,会<div key={this.state.heartHeight} className="HeartFill" style={styleHeartFill}></div>在现有的之后添加一个新的 React 组件 id。

但我希望那里永远只有一个<div className="HeartFill">

为什么会这样???

PS。单击几下后,结果将如下所示:

  <span data-reactid=".0.4.$8de89f4f1403aee7a963122b06de3712.3.0.0.2">
<div class="HeartFill HeartFill-enter HeartFill-enter-active" style="position:absolute;bottom:0;left:0;width:30px;height:3.5999999999999996px;background-color:#D64541;" data-reactid=".0.4.$8de89f4f1403aee7a963122b06de3712.3.0.0.2.$=1$6:0"></div>
<div class="HeartFill HeartFill-enter HeartFill-enter-active" style="position:absolute;bottom:0;left:0;width:30px;height:3px;background-color:#D64541;" data-reactid=".0.4.$8de89f4f1403aee7a963122b06de3712.3.0.0.2.$=1$5:0"></div>

    var HEIGHT_HEART = 30;
   var NUM_HEART_MAX = 50;

   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;


  var Heart = React.createClass({

getInitialState: function() {
    return {
        heartHeight: 0
    };
},

onClick: function(e) {
    var currentHeartHeight = this.state.heartHeight;
    this.setState({
        heartHeight: currentHeartHeight + 1
    });
},

render: function() {

    var styleHeartFill = {
        'position': 'absolute',
        'bottom': 0,
        'left': 0,
        'width': 30,
        'height': this.state.heartHeight / NUM_HEART_MAX * HEIGHT_HEART,
        'background-color': '#D64541'
    };


    return (
        <div className="Heart" >
                <div className="HeartControl" onClick={this.onClick}>
                    <i className="fa fa-angle-up" />
                </div>
            <img src="heart.png" className="HeartOutline" />
            <ReactCSSTransitionGroup transitionName="HeartFill">
                <div key={this.state.heartHeight} className="HeartFill" style={styleHeartFill}></div>
            </ReactCSSTransitionGroup>
        </div>
    );
 }

     });
    React.renderComponent(<Heart />, document.getElementById('Heart'));

`

4

5 回答 5

2

我怀疑你得到不止一个的原因是因为你使用了 key prop

<div key={this.state.heartHeight} className="HeartFill" style={styleHeartFill}></div>

来自 React 文档http://facebook.github.io/react/docs/multiple-components.html#dynamic-children

当 React 协调键控子级时,它将确保任何具有键的子级都将被重新排序(而不是破坏)或销毁(而不是重用)。

这是一个使用关键道具http://jsfiddle.net/kb3gN/3826/的 jsfiddle

这是一个不使用密钥道具的 jsfiddle http://jsfiddle.net/kb3gN/3827/

Ps 我在小提琴中做了一些改变,只是为了更好地展示推理

于 2014-07-18T18:47:47.130 回答
1

我的这个答案已经很晚了,但我也遇到了这个问题,并想为其他人提供解决方案。删除键不是一个足够的解决方案,因为 React 依赖它来知道何时为项目设置动画。该文档现在有一个部分不鼓励这样做。

您必须为 ReactCSSTransitionGroup 的所有子项提供 key 属性,即使仅呈现单个项目也是如此。这就是 React 将如何确定哪些孩子进入、离开或留下的方式。- https://facebook.github.io/react/docs/animation.html

如果您只是为单个项目的进入/退出设置动画,则可以使用 CSS hack 来修复可能从多个项目进入/退出时看到的闪烁。

.HeartFill {
    display: none;
}
.HeartFill:first-child {
    display: block;
}

在大多数情况下,React 会在顶部添加新元素,但这并不能保证。如果您的transitionEndTimeout道具设置为相对较短的时间,这应该不是一个大问题。timeout 属性也应该匹配 CSS 转换时间。

于 2016-08-12T05:45:25.797 回答
0

ReactCSSTransitionGroup 应该创建第二个元素

它会在指定的 css 动画完成时将其删除,或者在 css 中没有动画时打印警告

也许看看 Low-level API 以获得更好的理解: http: //facebook.github.io/react/docs/animation.html(页面底部)

于 2014-08-30T02:21:23.577 回答
0

这是问题所在:

您正在为随时间变化的键提供一个值。键用于确定元素是相同还是不同。

<div key={this.state.heartHeight} className="HeartFill" style={styleHeartFill}></div>

当你这样做时,键的值会发生变化,React 认为一个新元素正在进入而一个旧元素正在离开。

通常你需要一个唯一的键,它可以是顺序的,也可以使用 Math.random() 生成。(请记住使用 getInitialState 或 DefaultProps 生成一次,而不是在渲染中,因为那样每次都会创建一个新密钥)。

元素的顺序是另一件可能有麻烦的事情。

从 React 的文档中:

In practice browsers will preserve property order except for properties that can be
parsed as a 32-bit unsigned integers. Numeric properties will be ordered sequentially
and before other properties. If this happens React will render components out of
order. This can be avoided by adding a string prefix to the key:
于 2014-07-31T13:15:00.897 回答
0

I used gluxon's advice as a starting point - what worked for me was removing the leave transition and making it display nothing:

.example-leave.example-leave-active { display: none; }
于 2016-11-02T16:36:07.850 回答