Monthly Archives: March 2016

ReactJS应用的 UI layout控制

首先,在开发React之前,我认为应该是一件不太难的事,因为有比较丰富的backbone.js, marionette.js的开发经验,再加上大体了解它的思想,简单的认为和定义View的render,template的方法大同小异,只不过用了JSX奇怪的语法用javascript来代替html形式的模版。
刚开始开发的时候,一个页面一个页面的像玩具一样的写,觉得还行,然后开始重构,把一些公共的部分,header,footer开始往layout组件上分配,然后一下子懵圈了,这怎么搞?直觉上把组件按照层次放应该可以吧,parent组件怎么render children组件呢?果然发现了this.props.children属性可以用在parent组件里用{this.props.children}来渲染children组件,写到这得时候还算顺利,然后,问题来了,NavBar的title属性需要在每个children组件里设置,{this.props.children}怎么把属性传递过去呢?还是在官方发现了https://facebook.github.io/react/docs/clone-with-props.html,相当不认同他开头的那句,这不是最常用的场景嘛

In rare situations, you may want to create a copy of a React element

当然这时候我还没用Redux,Redux,Redux,重要的事情说三遍,所以我传了个setTitle的回调函数过去,在children组件的componentDidMount调用setTitle设置header的title,此时对React略有失望,尽管用javascript来代替html——相比较其他拼命加自定义属性来扩展html标签的语义——的思路是创新的,但也正是以组件为单位的思路导致了这种丑陋的,仅仅是为了从parent传递数据到children就得执行一个重量级的cloneElement操作,Redux的出现简直是挽救了React,如果没有Redux,React只是一个非常平凡的框架。回到项目,大致的路由设计如下,Home,Foo组件使用Layout,Bar组件有嵌套在Layout/Layout2中,

<Route  component={Layout}>
    <Route path="/"  component={Home} />
    <Route path="/foo" component={Foo} />
    <Route component={Layout2} >
        <Route path="/bar" component={Bar} />
    </Route>
</Route>

Layout组件的实现如下,

const Layout = React.createClass({
    ...
    ...
    setTitle: function(title){
        this.setState({title:title});
    }

render:function(){
    let childrenWithProps = React.Children.map(this.props.children, (child) => {
    return React.cloneElement(child, { setTitle: this.setTitle.bind(this) });
});
return (
    <div id="content">
        <NavBar title={this.state.title}/>
            {childrenWithProps}
        <FooterBar/>
    </div>
    )
    }
});