【问题标题】:Juggling Animations and View Hierarchy in React在 React 中处理动画和视图层次结构
【发布时间】:2015-07-11 04:00:44
【问题描述】:

我对 React 感到有些沮丧,因为视图层次结构破坏了我的动画。

我有一个<Layout> 组件,它设置了一个tab-nav 布局,它的子元素被放置在布局的内容部分中。它是一个纯组件,具有 titlesetTabcurrentTab 的 props。

如果我从视图层次结构和单向数据流的角度考虑这一点,我会将布局设置为每个视图的子视图,以便视图可以设置标题、当前选项卡和 setTab 可以是委托给其父级。

这基本上就是我正在做的事情:

var A = React.createClass({
  propTypes: {
    setTab: React.PropTypes.func.isRequired
  },
  render: function() {
    return (
      <Layout title="A Page" currentTab="A" setTab={this.props.setTab}>
        This is A
      </Layout>           
    )
  }
});

现在你可以使用 React Router 之类的东西作为标签,但是现在,我只有一个简单的顶级组件切换标签及其状态:

var App = React.createClass({
  getInitialState: function() {
    return {
      currentTab: 'A'
    }
  },
  setTab: function(name) {
    this.setState({currentTab:name})
  },
  render: function() {
    var component = false
    if (this.state.currentTab == 'A') {
      return <A setTab={this.setTab}/>
    } else {
      return <B setTab={this.setTab}/>
    }
  }
});

在您想开始添加一些动画之前,这一切都很好。

在我的&lt;Layout&gt; 组件中,我有一个高亮块,我想在标签之间切换时从左到右设置动画。

        <div className="tabbar">
          <div className={"highlight " + this.props.currentTab}></div>
          <div className="tabs">
            <div className="tab" onClick={() => {this.props.setTab('A')}}>A</div>
            <div className="tab" onClick={() => {this.props.setTab('B')}}>B</div>
          </div>
        </div>

这是该动画的 CSS:

.highlight {
    border-bottom: 3px solid red;
    width: 50%;
    position: absolute;
    top: 0;
    bottom: 0;
    transition: left .25s ease-in-out;
}
.highlight.A {
    left: 0;
}
.highlight.B {
    left: 50%;
}

我也在尝试使用 React.addons.CSSTransitionGroup 为布局的标题设置动画,但我认为问题是一样的:

这里的问题似乎是 &lt;Layout&gt; 组件每次都完全重新渲染,因为渲染树的根(&lt;A/&gt;&lt;B/&gt;)正在改变。

所以现在的问题是,我如何反转视图层次结构,以便 &lt;Layout&gt; 不会不断重新渲染,以便动画可以工作?

注意:在一个不太人为的例子中,布局还可以从&lt;A/&gt; 获取其他道具,例如 onClick 处理程序。

这是一个 JSFiddle,展示了我的挫败感:

https://jsfiddle.net/ccorcos/3rupb0og/

【问题讨论】:

    标签: javascript animation reactjs


    【解决方案1】:

    好的。我想出了一些可行的方法,但我不确定这是否是最佳做法,所以在我得出结论之前,我非常感谢一些反馈。

    我提出了stitch 的概念,作为通过组件层次结构拼接 函数的一种方式。这将允许我从子组件设置父组件的状态。

    function stitch() {
      return {
        to: (f) => {
          this.func = f
        },
        from: () => {
          this.func.apply(null, arguments)
        }
      }
    }
    

    所以现在我的&lt;Layout&gt; 看起来像这样:

    var Layout = React.createClass({
      propTypes: {
        currentTab: React.PropTypes.string.isRequired,
        onTab: React.PropTypes.func.isRequired,
        stitchTitle: React.PropTypes.string.isRequired
      },
      getInitialState: function() {
        return {
          title: ''
        }
      },
      componentWillMount: function() {
        this.props.stitchTitle((title) => {
          this.setState({title})
        })
      },
      // ...
    }
    

    视图看起来像这样:

    var A = React.createClass({
      propTypes: {
        setTitle: React.PropTypes.func.isRequired
      },
      componentWillMount: function() {
        this.props.setTitle('Page A')
      },
      //...
    }
    

    我们所要做的就是将它们缝合在一起。

    var App = React.createClass({
      getInitialState: function() {
        return {
          currentTab: 'A'
        }
      },
      setTab: function(name) {
        this.setState({currentTab:name})
      },
      componentWillMount: function() {
        this.titleStitch = stitch()
      },
      render: function() {
        var view = false
        if (this.state.currentTab == 'A') {
          view = <A setTitle={this.titleStitch.from}/>
        } else {
          view = <B setTitle={this.titleStitch.from}/>
        }
        return (
          <Layout currentTab={this.state.currentTab} onTab={this.setTab} stitchTitle={this.titleStitch.to}>
            {view}
          </Layout>  
        )
      }
    });
    

    果然成功了!这是 JSFiddle:

    https://jsfiddle.net/ccorcos/bLtuLdwh/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-07
      相关资源
      最近更新 更多