React.js编程思想
JavaScript框架层出不穷,在很多程序员看来,React.js是创建大型、快速的Web应用的最好方式。这一款由Facebook出品的JS框架,无论是在Facebook还是在Instagram中,它的表现都非常出色。
使用React.js的好处多多,但是其中非常好的一部分是它能够让你重新思考如何创建一个web应用。在本文中,我们将通过一步一步的创建一个产品数据表,并以此过程带领你思考和领悟React.js的编程思想。
步骤零:创建一些伪数据
假设现在我们已经有了一个JSON API和一些伪数据。如下图所示。当然,现在的设计看起来非常糟糕,但是它可以体现出我们将要创建的应用结构:
同时,我们可以通过JSON API返回下列数据:
[ {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"}, {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"}, {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"}, {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"}, {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"}, {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"} ];
第一步 –将你的UI打散为层级组件
你需要做的第一件事情是在每一个组件(以及子组件)周围画上一个框,然后给每个组件起一个名字。如果设计图是由一个设计师给你的,他通常已经帮你完成了这件事情,因此你可以跑去问他设计图中各个层的名字,并以这些名字为你的React组件命名。
但是我们怎么知道哪些部分应该是一个组件呢?想象一下,加入你现在不是在创建一个应用,而是在创建一个新的函数或者对象,你会怎么做。在这里,我们最好遵循”单一任务原则”,也就是说,一个组件最好只是做一件事情。如果一个组件的任务有所增加,那么你应该考虑是不是要把这个组件拆成几个更小的组件。
由于你经常需要讲一个JSON数据模型展示给用户,因此你需要检查这个模型结构是否正确以便你的UI(在这里指的就是你的组件结构)是否能够正确的映射到这个模型上。这是因为用户界面和数据模型在信息构造方面都要一直,这意味着将你可以省下很多将UI分割成组件的麻烦事。你需要做的仅仅只是将数据模型分隔成一小块一小块的组件以便它们都能够表示成组件。
在上面的示意图中,你可以看到在我们这个简单的应用中,包含着5个组件:
- FilterableProductTable(橙色): 包含着整个例子
- SearchBar(蓝色): 接收用户的输入
- ProductTable(绿色): 基于用户输入展示和过滤数据集合
- ProductCategoryRow(青色): 为每一种类型展示一个头部数据
- ProductRow(红色): 为每种产品展示一行
如果你注意看ProductTable
,你将会看到表头(就是包含着”Name”和”Price”标签的部分)并不是单独一个组件。这并不是什么硬性规定,无论你是否将这部分单独隔离出来都没有错。但是在这个例子中,我们将它作为ProductTable
的一个部分,因为它是渲染数据集合的一个部分,而这是ProductTable
的任务。然而,如果表头变得很复杂(例如,如果我们在其中添加了排序功能),那么你应该毫不犹豫的将它作为一个单独的ProductTableHeader
组件。
现在我们已经理清楚了我们的应用中的组件。我们可以简单的将它们做一个层级排序,如下所示:
- FilterableProductTable - SearchBar - ProductTable - ProductCategoryRow - ProductRow
步骤二:使用React创建一个静态版本的应用
/** @jsx React.DOM */ var ProductCategoryRow = React.createClass({ render: function() { return (<tr><th colSpan="2">{this.props.category}</th></tr>); } }); var ProductRow = React.createClass({ render: function() { var name = this.props.product.stocked ? this.props.product.name : <span style={{color: 'red'}}> {this.props.product.name} </span>; return ( <tr> <td>{name}</td> <td>{this.props.product.price}</td> </tr> ); } }); var ProductTable = React.createClass({ render: function() { var rows = []; var lastCategory = null; this.props.products.forEach(function(product) { if (product.category !== lastCategory) { rows.push(<ProductCategoryRow category={product.category} key={product.category} />); } rows.push(<ProductRow product={product} key={product.name} />); lastCategory = product.category; }); return ( <table> <thead> <tr> <th>Name</th> <th>Price</th> </tr> </thead> <tbody>{rows}</tbody> </table> ); } }); var SearchBar = React.createClass({ render: function() { return ( <form> <input type="text" placeholder="Search..." /