@brizer
2016-02-16T09:04:49.000000Z
字数 5306
阅读 1264
前面对React的基本用法学习得差不多,这里通过官网的一个demo来实现一个较为复杂的组件。
先看看原型稿:
JSON数据格式:
[{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"}];
设计思路是将组件尽可能小而细:
五个组件:
FilterableProductTable (橘色): 包含整个例子的容器
SearchBar (蓝色): 接受所有 用户输入( user input )
ProductTable (绿色): 根据 用户输入( user input ) 过滤和展示 数据集合( data collection )
ProductCategoryRow (青色): 为每个 分类( category ) 展示一列表头
ProductRow (红色): 为每个 产品( product ) 展示一列
他们的层级关系如下:
FilterableProductTable
--SearchBar
--ProductTable
----ProductCategoryRow
----ProductRow
我们先定义一个静态的页面:
//种类标题组件var ProductCategoryRow = React.createClass({render:function(){return (<tr><th colSpan="2">this.props.category</th></tr>)}});//产品组件var ProductRow = React.createClass({render:function(){//如果我=stocked为false,则标红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..."/><p><input type="checkbox" />{' '}Only show products in stocked</p></form>);}});//主组件var FilterableProductTable = React.createClass({render:function(){return (<div><SearchBar /><ProductTable products={this.props.products} /></div>);}});//定义数据var PRODUCTS = [{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'}];ReactDOM.render(//将数据通过products属性传递下去<FilterableProductTable products={PRODUCTS} />,document.getElementById('example'));
效果如下:
不过这是一个静态版本,所以我们只用到了props就将父级的数据传递到了各个子级。如果我们要交互,就需要使用state。
我们需要找出哪些组件属性会改变,就改用state,不改变的我们就应该尽量使用props。
首先我们为主组件添加必要的state,修改如下:
//主组件var FilterableProductTable = React.createClass({getInitialState: function() {return {filterText: '',inStockOnly: false};},render: function() {return (<div><SearchBarfilterText={this.state.filterText}inStockOnly={this.state.inStockOnly}/><ProductTableproducts={this.props.products}filterText={this.state.filterText}inStockOnly={this.state.inStockOnly}/></div>);}});
对应的搜索组件通过主组件的state进行对应判断:
//搜索组件var SearchBar = React.createClass({render: function() {return (<form><input type="text" placeholder="Search..." value={this.props.filterText} /><p><input type="checkbox" checked={this.props.inStockOnly} />{' '}Only show products in stock</p></form>);}});
还有表格组件:
//呈现表格组件var ProductTable = React.createClass({render: function() {var rows = [];var lastCategory = null;this.props.products.forEach(function(product) {//过滤产品if (product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) {return;}//保证产品类型一致的产品if (product.category !== lastCategory) {rows.push(<ProductCategoryRow category={product.category} key={product.category} />);}rows.push(<ProductRow product={product} key={product.name} />);lastCategory = product.category;}.bind(this));return (<table><thead><tr><th>Name</th><th>Price</th></tr></thead><tbody>{rows}</tbody></table>);}});
我们决定了 state 数据模型位于 FilterableProductTable 之中。首先,给 FilterableProductTable 添加 getInitialState() 方法,该方法返回 {filterText: '', inStockOnly: false} 来反映应用的初始化状态。然后传递 filterText 和 inStockOnly 给 ProductTable 和 SearchBar 作为 prop 。最后,使用这些 props 来过滤 ProductTable 中的行,设置在 SearchBar 中表单字段的值。
接下来我们需要对自己的查询条件进行反馈。首先在主组件中添加处理事件并反馈到子组件:
//主组件var FilterableProductTable = React.createClass({//初始化stategetInitialState: function() {return {filterText: '',inStockOnly: false};},//处理statehandleUserInput:function(filterText,inStockOnly){this.setState({filterText:filterText,inStockOnly:inStockOnly});},render: function() {return (<div><SearchBarfilterText={this.state.filterText}inStockOnly={this.state.inStockOnly}// 传递事件onUserInput={this.handleUserInput}/><ProductTableproducts={this.props.products}filterText={this.state.filterText}inStockOnly={this.state.inStockOnly}/></div>);}});
然后在搜索组件中,通过onChange触发将state值回调到父级:
//搜索组件var SearchBar = React.createClass({handleChange:function(){this.props.onUserInput(this.refs.filterTextInput.value,this.refs.inStockOnlyInput.checked);},render: function() {return (<form><inputtype="text"placeholder="Search..."value={this.props.filterText}ref="filterTextInput"onChange={this.handleChange}/><p><inputtype="checkbox"checked={this.props.inStockOnly}ref="inStockOnlyInput"onChange={this.handleChange}/>{' '}Only show products in stock</p></form>);}});
最后整个组件功能完成。
demo