从设计稿到实现React应用(分类数据处理)

1. 确定设计稿和数据

设计稿:

 数据:

[
  {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"}
];

2. 将设计稿UI分组件层级

组件单一功能原则:

即一个组件实现一个功能。

 

 

 图中,一个颜色是一种组件,按照嵌套关系,可以分为:

FilterableProductTable:

   SearchBar:

   ProductTable:

       ProductCategoryRow

       ProductRow

3. 确定需要的state值的个数

   原则:

1. 值不是来自与props
2. 值不是一成不变
3. 值不能由其他state和props求得

该示例中,需要数据源的地方有:

1. 查询框的文本 // 会变化;state.filterText          
2. 复选框的状态 // 会变化;state.isStock
3. 所有的产品列表数据  // 通过props传入; 无state
4. 过滤后的产品列表数据  //通过1,2,3获得; 无state

4. 确定state的位置-状态提升

通过分析state对应的值作用的范围,state应该位于所有作用区域的父组件;

才能共享state。

从功能分析,1,2的状态会影响列表展示;则其应该位于查询框和列表的父组件;

即组件FilterableProductTable中。

3的状态会影响列表分类ProductCategoryRow和列表项ProductRow,则应该放在他们的父组件;

即组件ProductTable中。

5. 添加反向数据流

即通过触发子组件的事件监听,调用父组件传递过去的函数,从而改变父组件的state的值。

因为state的状态提升,而state又是私有状态,只能通过state所处的组件的函数进行修改。

6. 从下向上编写代码

/*
 * @Author: LyraLee
 * @Date: 2019-11-08 09:01:58
 * @LastEditTime: 2019-11-20 17:32:14
 * @Description: 分类数据处理
 */
'use strict'
const products = [
  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];
function ProductRow(props) {
  const product = props.product;
  const { name } = product;
  const renderName = !product.stocked ? <span style={{color: 'red'}}>{name}</span> : name
  return (
    <tr>
      <td>{renderName}</td>
      <td>{product.price}</td>
    </tr>
  )
}
function ProductCategoryRow(props) {
  const product = props.product;
  return(
    <tr>
      <th colSpan="2">{product.category}</th>
    </tr>
  )
}
function ProductTable(props) {
  const { filterText, isStockedOnly, products } = props;
  // 处理数据的方法!!!需要分类的属性是category,
  // 如果数据不是按照该属性排序,那先将其按照category的字段顺序
  let lastCategory = null;
  let rows = []
  products.sort((a,b) => a.category.localeCompare(b.category))
  .forEach(product => {
    if (!product.name.includes(filterText)) {
      return;
    }
    if (isStockedOnly && !product.stocked) {
      return;
    }
    if (product.category !== lastCategory) {
      rows.push(<ProductCategoryRow key={product.category} product={product} />)
    }
    rows.push(
      <ProductRow key={product.name} product={product} />
    )
    lastCategory = product.category;
  });

  return (
    <table>
      <thead>
        <tr>
          <th>name</th>
          <th>price</th>          
        </tr>
      </thead>
      <tbody>
        {rows}
      </tbody>
    </table>
  )
}
function SearchBar(props) {
  function handleChange (e) {
    const { name, type } = e.target;
    const value = type === 'checkbox' ? e.target.checked : e.target.value;
    props.handleChange(name, value);
  }
  const { filterText, isStockedOnly } = props; 
  return(
    <div>
      <input 
        name="filterText"
        type="text" 
        value={filterText} 
        onChange={handleChange}
        placeholder="search..."
      />
      <p>
        <input 
          name="isStockedOnly"
          type="checkbox"
          checked={isStockedOnly}
          onChange={handleChange}
        />{' '}
        Only show products in stock        
      </p>
    </div>
  )
}
class FileterableProductTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      filterText: '',
      isStockedOnly: false
    }
  }
  handleChange = (name, value) => {
    this.setState({
      [name]: value
    })
  }
  render() {
    const { filterText, isStockedOnly } = this.state;
    const { products } = this.props;
    return(
      <React.Fragment>
        <SearchBar
          filterText={filterText}
          isStockedOnly={isStockedOnly}
          handleChange={this.handleChange}
        />
        <ProductTable
          filterText={filterText}
          isStockedOnly={isStockedOnly}
          products={products}
        />
      </React.Fragment>
    )
  }
}

ReactDOM.render(<FileterableProductTable products={products} />, root); 

 

posted @ 2019-11-20 17:34  Lyra李  阅读(280)  评论(0编辑  收藏  举报