[关闭]
@brizer 2016-01-31T15:54:10.000000Z 字数 5306 阅读 1569

React之深入组件实现


前言

前面对React的基本用法学习得差不多,这里通过官网的一个demo来实现一个较为复杂的组件。


确定结构

先看看原型稿:

JSON数据格式:

  1. [
  2. {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  3. {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  4. {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  5. {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  6. {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  7. {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
  8. ];

设计思路是将组件尽可能小而细:

五个组件:

FilterableProductTable (橘色): 包含整个例子的容器
SearchBar (蓝色): 接受所有 用户输入( user input )
ProductTable (绿色): 根据 用户输入( user input ) 过滤和展示 数据集合( data collection )
ProductCategoryRow (青色): 为每个 分类( category ) 展示一列表头
ProductRow (红色): 为每个 产品( product ) 展示一列

他们的层级关系如下:

FilterableProductTable
--SearchBar
--ProductTable
----ProductCategoryRow
----ProductRow


设置props

我们先定义一个静态的页面:

  1. //种类标题组件
  2. var ProductCategoryRow = React.createClass({
  3. render:function(){
  4. return (<tr><th colSpan="2">this.props.category</th></tr>)
  5. }
  6. });
  7. //产品组件
  8. var ProductRow = React.createClass({
  9. render:function(){
  10. //如果我=stocked为false,则标红
  11. var name = this.props.product.stocked ?
  12. this.props.product.name:
  13. <span style={{color:'red'}}>
  14. {this.props.product.name}
  15. </span>;
  16. return (
  17. <tr>
  18. <td>{name}</td>
  19. <td>{this.props.product.price}</td>
  20. </tr>
  21. );
  22. }
  23. });
  24. //呈现表格组件
  25. var ProductTable = React.createClass({
  26. render:function(){
  27. var rows = [];
  28. var lastCategory = null;
  29. this.props.products.forEach(function(product){
  30. //确保同一类似产品在同一标题组件下
  31. if(product.category !== lastCategory){
  32. rows.push(<ProductCategoryRow category={product.category} key={product.category} />);
  33. }
  34. rows.push(<ProductRow product={product} key={product.name} />);
  35. lastCategory = product.category;
  36. });
  37. return (
  38. <table>
  39. <thead>
  40. <tr>
  41. <th>Name</th>
  42. <th>Price</th>
  43. </tr>
  44. </thead>
  45. <tbody>
  46. {rows}
  47. </tbody>
  48. </table>
  49. );
  50. }
  51. });
  52. //搜索框组件
  53. var SearchBar = React.createClass({
  54. render:function(){
  55. return (
  56. <form>
  57. <input type="text" placeholder="Search..."/>
  58. <p>
  59. <input type="checkbox" />
  60. {' '}
  61. Only show products in stocked
  62. </p>
  63. </form>
  64. );
  65. }
  66. });
  67. //主组件
  68. var FilterableProductTable = React.createClass({
  69. render:function(){
  70. return (
  71. <div>
  72. <SearchBar />
  73. <ProductTable products={this.props.products} />
  74. </div>
  75. );
  76. }
  77. });
  78. //定义数据
  79. var PRODUCTS = [
  80. {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
  81. {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
  82. {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
  83. {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
  84. {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
  85. {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
  86. ];
  87. ReactDOM.render(
  88. //将数据通过products属性传递下去
  89. <FilterableProductTable products={PRODUCTS} />,
  90. document.getElementById('example')
  91. );

效果如下:


添加state

不过这是一个静态版本,所以我们只用到了props就将父级的数据传递到了各个子级。如果我们要交互,就需要使用state。
我们需要找出哪些组件属性会改变,就改用state,不改变的我们就应该尽量使用props。

首先我们为主组件添加必要的state,修改如下:

  1. //主组件
  2. var FilterableProductTable = React.createClass({
  3. getInitialState: function() {
  4. return {
  5. filterText: '',
  6. inStockOnly: false
  7. };
  8. },
  9. render: function() {
  10. return (
  11. <div>
  12. <SearchBar
  13. filterText={this.state.filterText}
  14. inStockOnly={this.state.inStockOnly}
  15. />
  16. <ProductTable
  17. products={this.props.products}
  18. filterText={this.state.filterText}
  19. inStockOnly={this.state.inStockOnly}
  20. />
  21. </div>
  22. );
  23. }
  24. });

对应的搜索组件通过主组件的state进行对应判断:

  1. //搜索组件
  2. var SearchBar = React.createClass({
  3. render: function() {
  4. return (
  5. <form>
  6. <input type="text" placeholder="Search..." value={this.props.filterText} />
  7. <p>
  8. <input type="checkbox" checked={this.props.inStockOnly} />
  9. {' '}
  10. Only show products in stock
  11. </p>
  12. </form>
  13. );
  14. }
  15. });

还有表格组件:

  1. //呈现表格组件
  2. var ProductTable = React.createClass({
  3. render: function() {
  4. var rows = [];
  5. var lastCategory = null;
  6. this.props.products.forEach(function(product) {
  7. //过滤产品
  8. if (product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) {
  9. return;
  10. }
  11. //保证产品类型一致的产品
  12. if (product.category !== lastCategory) {
  13. rows.push(<ProductCategoryRow category={product.category} key={product.category} />);
  14. }
  15. rows.push(<ProductRow product={product} key={product.name} />);
  16. lastCategory = product.category;
  17. }.bind(this));
  18. return (
  19. <table>
  20. <thead>
  21. <tr>
  22. <th>Name</th>
  23. <th>Price</th>
  24. </tr>
  25. </thead>
  26. <tbody>{rows}</tbody>
  27. </table>
  28. );
  29. }
  30. });

我们决定了 state 数据模型位于 FilterableProductTable 之中。首先,给 FilterableProductTable 添加 getInitialState() 方法,该方法返回 {filterText: '', inStockOnly: false} 来反映应用的初始化状态。然后传递 filterTextinStockOnlyProductTableSearchBar 作为 prop 。最后,使用这些 props 来过滤 ProductTable 中的行,设置在 SearchBar 中表单字段的值。


反馈state的值

接下来我们需要对自己的查询条件进行反馈。首先在主组件中添加处理事件并反馈到子组件:

  1. //主组件
  2. var FilterableProductTable = React.createClass({
  3. //初始化state
  4. getInitialState: function() {
  5. return {
  6. filterText: '',
  7. inStockOnly: false
  8. };
  9. },
  10. //处理state
  11. handleUserInput:function(filterText,inStockOnly){
  12. this.setState({
  13. filterText:filterText,
  14. inStockOnly:inStockOnly
  15. });
  16. },
  17. render: function() {
  18. return (
  19. <div>
  20. <SearchBar
  21. filterText={this.state.filterText}
  22. inStockOnly={this.state.inStockOnly}
  23. // 传递事件
  24. onUserInput={this.handleUserInput}
  25. />
  26. <ProductTable
  27. products={this.props.products}
  28. filterText={this.state.filterText}
  29. inStockOnly={this.state.inStockOnly}
  30. />
  31. </div>
  32. );
  33. }
  34. });

然后在搜索组件中,通过onChange触发将state值回调到父级:

  1. //搜索组件
  2. var SearchBar = React.createClass({
  3. handleChange:function(){
  4. this.props.onUserInput(
  5. this.refs.filterTextInput.value,
  6. this.refs.inStockOnlyInput.checked
  7. );
  8. },
  9. render: function() {
  10. return (
  11. <form>
  12. <input
  13. type="text"
  14. placeholder="Search..."
  15. value={this.props.filterText}
  16. ref="filterTextInput"
  17. onChange={this.handleChange}
  18. />
  19. <p>
  20. <input
  21. type="checkbox"
  22. checked={this.props.inStockOnly}
  23. ref="inStockOnlyInput"
  24. onChange={this.handleChange}
  25. />
  26. {' '}
  27. Only show products in stock
  28. </p>
  29. </form>
  30. );
  31. }
  32. });

最后整个组件功能完成。
demo


参考

深入理解React

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注