One of the best parts of React is that it leads us to think about how to build an app. In this document, we will build a searchable product data table with React to gain a deeper understanding of React philosophy. Refer to the official documentation links for this article

  • Thinking about technology realization from product application

    • Let’s say we have this design sketch

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"}];Copy the code

  1. FilterableProductTable (orange): the entire sample application as a whole
  2. SearchBar (blue): Accepts all user input
  3. ProductTable (green): displays data content and filters results based on user input
  4. ProductCategoryRow (sky blue): Displays the title for each product category
  5. ProductRow (red): Each line shows one product

Abstract level

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

Now let’s show it in code

Put the shelf up

Too much. See Codepen Codepen

Determine the state [state]

What is a state? We can let the user is | | no click, a user’s search and these are the dynamic state, dynamic state corresponding to the above minimize UI, corresponding to the above is according to the state of the blue box to change the green box profile is: data driven view

State is on that level

Note: Complex cross-component interactions such as context, redux and Mobx are not involved in React component design considerations.

  • Find all the components that render according to this state.
  • Find their common owner component (above all components that require this state at the component level).
  • The co-owner component, or a component higher than it, should own the state.
  • If you can’t find a suitable place to store the state, you can simply create a new component to store the state and place the new component above the co-owner component hierarchy.

Reconsider our sample application in light of the above strategy:

  • ProductTable needs to filter the list of products by state. The SearchBar needs to show the status of the search term and the check box.
  • Their co-owner is FilterableProductTable.
  • Therefore, the search terms and check box values should naturally be stored in the FilterableProductTable component.
  • Well, we’ve decided to store these states in the FilterableProductTable component. First, add the instance property this.state = {filterText: “, inStockOnly: false} to constructor of FilterableProductTable to set the initial state of the application; Next, pass filterText and inStockOnly as props to ProductTable and SearchBar; Finally, use these props to filter the product information in the ProductTable and set the form value for the SearchBar.

Reverse data flow

We know that React is a one-way data stream which is the data changes the view changes, but the input changes in the view and our data hasn’t changed yet, so we need to implement that, and we need to trigger the FN to change the listening data in the state, so we can change the view

Finally, the complete code is posted

Codepen online

class ProductCategoryRow extends React.Component {
  render() {
    const category = this.props.category;
    return (
      <tr>
        <th colSpan="2">
          {category}
        </th>
      </tr>); }}class ProductRow extends React.Component {
  render() {
    const product = this.props.product;
    const name = product.stocked ?
      product.name :
      <span style={{color: 'red'}} >
        {product.name}
      </span>;

    return (
      <tr>
        <td>{name}</td>
        <td>{product.price}</td>
      </tr>); }}class ProductTable extends React.Component {
  render() {
    const filterText = this.props.filterText;
    const inStockOnly = this.props.inStockOnly;

    const rows = [];
    let lastCategory = null;

    this.props.products.forEach((product) = > {
      if (product.name.indexOf(filterText) === - 1) {
        return;
      }
      if(inStockOnly && ! product.stocked) {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; }); return ( <table> <thead> <tr> <th>Name</th> <th>Price</th> </tr> </thead> <tbody>{rows}</tbody> </table> ); } } class SearchBar extends React.Component { constructor(props) { super(props); this.handleFilterTextChange = this.handleFilterTextChange.bind(this); this.handleInStockChange = this.handleInStockChange.bind(this); } handleFilterTextChange(e) { this.props.onFilterTextChange(e.target.value); } handleInStockChange(e) { this.props.onInStockChange(e.target.checked); } render() { return ( <form> <input type="text" placeholder="Search..." value={this.props.filterText} onChange={this.handleFilterTextChange} /> <p> <input type="checkbox" checked={this.props.inStockOnly} onChange={this.handleInStockChange} /> {' '} Only show products in stock </p> </form> ); } } class FilterableProductTable extends React.Component { constructor(props) { super(props); this.state = { filterText: '', inStockOnly: false }; this.handleFilterTextChange = this.handleFilterTextChange.bind(this); this.handleInStockChange = this.handleInStockChange.bind(this); } handleFilterTextChange(filterText) { this.setState({ filterText: filterText }); } handleInStockChange(inStockOnly) { this.setState({ inStockOnly: inStockOnly }) } render() { return ( <div> <SearchBar filterText={this.state.filterText} inStockOnly={this.state.inStockOnly} onFilterTextChange={this.handleFilterTextChange} onInStockChange={this.handleInStockChange} /> <ProductTable products={this.props.products} filterText={this.state.filterText} inStockOnly={this.state.inStockOnly} /> </div> ); }} const PRODUCTS = [{category: 'Sporting Goods', price: '$49.99', tag: true, tag: 'Football'}, {category: 'Sporting Goods', price: '$49.99', tag: true, tag: 'Football'}, 'Sporting Goods', price: '$9.99', tag: true, name: 'Baseball'}, category: 'Sporting Goods', price: '$9.99', tag: true, name: 'Baseball'}, category: 'Sporting Goods', price: '$29.99', tempt: false, name: 'Basketball'}, {category: 'Electronics', price: '$99.99', tempt: true, name: 'Basketball' }, {category: 'Electronics', price: '$399.99', hot: false, name: 'iPhone 5'}, {category: 'iPod Touch', price: '$399.99', 'Electronics', price: '$199.99', SWB: true, name: 'Nexus 7'}]; ReactDOM.render( <FilterableProductTable products={PRODUCTS} />, document.getElementById('container') );Copy the code