zoukankan      html  css  js  c++  java
  • 跟着官网的例子学Reacjs (一)FilterableProductTable

      最近开始学习React,发现最好的方法不是看这个书那个书,而是直接上官网,一步步的跟着学习,真的获益匪浅。许多翻译的书上漏掉的知识点都可以学到。

    入门的一些准备工作可以参照官网的步骤,引入依赖的核心包,就不多说了,直接上官网的第二个具体例子,一个过滤产品列表的Table:https://facebook.github.io/react/docs/thinking-in-react.html

         这篇文章主要介绍的并不是API的一些使用,而是向刚入门的同学介绍使用React设计组件时的一些思路,思考怎么样来更好的使用React。

      1. 首先,要做的是这么个东西

    一个很简单的table列表,带了一个搜索功能,只是界面比较简陋。。。(作者自己也调侃说这肯定是个糟糕的设计,哈哈)。鉴于此,使用bootstrap稍微规整了一下

      2. 接着,作者分析了这个组件该怎么划分:要本着最小原则,实现单一功能得原则,划分了五个组件

    每种颜色代表一个组件,最后组件的关系如下,很好理解:

    FilterableProductTable

    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

    下面直接进入主题,来code这五个组件

      2.1 先来个最简单的,SearchBar

      这个组件和其他的组件相对独立,而且就一个input框和一个复选框

     1 var SearchBar = React.createClass({
     2     render: function () {
     3         return (
     4             <form>
     5                 <input type="text" placeholder="input product name"/><br/>
     6                 <input id="FPT_SearchBar_in_stock" type="checkbox"/>
     7                 <label htmlFor="FPT_SearchBar_in_stock">only show product in stock</label>
     8             </form>
     9         );
    10     }
    11 });

    render方法只渲染了一个form,里面一个俩input,搞定

      2.2 ProductCategoryRow

    产品分类组件,也相对简单些,只需要接受父组件的一个分类的名称就可以了

    1 var ProductCategoryRow = React.createClass({
    2     render:function(){
    3         return (
    4             <tr>
    5                 <th colSpan="2">{this.props.category}</th>
    6             </tr>
    7         );
    8     }
    9 });

      2.3 ProductRow

    产品明细组件,接受父类的产品信息,并且判断,如果没有库存了,产品名字要显示为红色

    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>
             );
        }
    });

      2.4 ProductTable

    产品列表组件负责渲染所有的产品信息,通过接收父类穿进来的products属性,遍历循环,并负责给两个子控件ProductCategoryRow 和 ProductRow 赋值

     1 var ProductTable = React.createClass({
     2     //根据数据获得需要render的rows
     3     formatProducts: function () {
     4         var result = [];
     5         var category = "";
     6         this.props.products.forEach((product)=> {
     7             if(category !== product.category){
     8                 result.push(<ProductCategoryRow category={product.category} key={product.category}/>);
     9             }
    10             result.push(<ProductRow product={product} key={product.name}/>);
    11             category = product.category;
    12         });
    13         return result;
    14     },
    15     render: function () {
    16         var products = this.formatProducts();
    17         return (
    18             <table className="table table-bordered">
    19                 <thead>
    20                     <tr>
    21                         <th>
    22                             Name
    23                         </th>
    24                         <th>
    25                             Price
    26                         </th>
    27                     </tr>
    28                 </thead>
    29                 <tbody>
    30                     {products}
    31                 </tbody>
    32             </table>
    33         );
    34     }
    35 });

      2.5 最后一个组件FilterableProductTable

    这个组件只负责给ProductTable的products属性赋值就可以了,然后把SearchBar组件也包含进来。

     1 var FilterableProductTable = React.createClass({
     2     render: function () {
     3         return (
     4             <div>
     5                 <SearchBar />
     6                 <ProductTable products={this.state.data}/>
     7             </div>
     8         );
     9     },
    10     getInitialState: function () {
    11         return {
    12             data: [],
    13             filterName: '',
    14             onlyStock: ''
    15         };
    16     },
    17     //组件显示后(生命周期中的方法)
    18     componentDidMount: function () {
    19         var defaultData = [
    20             {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
    21             {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
    22             {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
    23             {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
    24             {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
    25             {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
    26         ];
    27         setTimeout(function () {
    28             this.setState({data: defaultData});
    29         }.bind(this), 2000);
    30     },
    31     addOneProduct: function () {
    32         var oldData = this.state.data;
    33         var newData = {category: "Electronics", price: "$123", stocked: true, name: (new Date) - 0};
    34         oldData.push(newData);
    35         this.setState({data: oldData});
    36     }
    37 });

    这里做了一些处理,就是每个组件都有一个生命周期,其中内置的函数componentDidMount函数负责在组件显示后调用,延迟2s给data传递了本地数据,这样就有一个过了两秒数据才加载出来的感觉

    通过上面的两步,页面一个纯静态的样子就出来了,过滤的功能还没有加。

    然后作者提到了一个关键的概念,就是React中的props和state,他俩的区别在哪?什么时候使用state?

    作者给出了一个解决的方法:

     让我们通过每一个问题,找出哪一个是state。简单地询问每一块数据三个问题:

    它是从通过父组件的props传递?如果是这样,它可能不是state。
    是否随着时间的推移保持不变?如果是这样,它可能不是state。
    你可以基于组件中的任何其他state或props计算它?如果是这样,它不是state。

    大概的翻译了一下原文,如上。这应该就是使用state的一个原则吧。

    接下来,开始实现过滤的功能之前,根据上面的原则,我们思考我们要实现的这几个组件中,到底有哪些地方要用到state?

    没错,一共3个:

    1、整个表格的数据来源,正常情况下是从服务器请求的,所以使用state

    2、SearchBar中的搜索框的输入值,因为是用户输入的,时刻在发生变化

    3、SearchBar中的复选框

      3、按照上面整理的,需要修改之前的两个组件

     1 var FilterableProductTable = React.createClass({
     2     render: function () {
     3         return (
     4             <div>
     5                 <SearchBar filterName={this.state.filterName} onlyStock={this.state.onlyStock} onSearchChange={this.handleSearchChange}/>
     6                 <ProductTable products={this.state.data} filterName={this.state.filterName} onlyStock={this.state.onlyStock}/>
     7             </div>
     8         );
     9     },
    10     getInitialState: function () {
    11         return {
    12             data: [],
    13             filterName: '',
    14             onlyStock: false
    15         };
    16     },
    17     //组件显示后(生命周期中的方法)
    18     componentDidMount: function () {
    19         var defaultData = [
    20             {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
    21             {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
    22             {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
    23             {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
    24             {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
    25             {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
    26         ];
    27         setTimeout(function () {
    28             this.setState({data: defaultData});
    29         }.bind(this), 2000);
    30     },
    31     //当搜索框变化时的处理函数
    32     handleSearchChange:function(filterName, onlyStock){
    33         this.setState({
    34             filterName: filterName,
    35             onlyStock: onlyStock
    36         });
    37     },
    38     addOneProduct: function () {
    39         var oldData = this.state.data;
    40         var newData = {category: "Electronics", price: "$123", stocked: true, name: (new Date) - 0};
    41         oldData.push(newData);
    42         this.setState({data: oldData});
    43     }
    44 });
     1 var SearchBar = React.createClass({
     2     render: function () {
     3         return (
     4             <form>
     5                 <input type="text" placeholder="input product name"
     6                        ref="filterTextInput"
     7                        value={this.props.filterName}
     8                        onChange={this.handleChange} /><br/>
     9                 <input id="FPT_SearchBar_in_stock" type="checkbox"
    10                        ref="inputOnlyStock"
    11                        checked={this.props.onlyStock}
    12                        onChange={this.handleChange} />
    13                 <label htmlFor="FPT_SearchBar_in_stock">only show product in stock</label>
    14             </form>
    15         );
    16     },
    17     handleChange:function(){
    18         this.props.onSearchChange(this.refs.filterTextInput.value, this.refs.inputOnlyStock.checked);
    19     }
    20 });

    OK,完成。

    完整代码可以到我的github上下载运行:https://github.com/lyc-chengzi/reactProject

    后续新的例子会继续往上整合,并且用webpack来打包,希望大家一起学习

  • 相关阅读:
    IOS应用内嵌cocos2dx游戏项目
    C++ 动态内存
    C++ 文件和流
    【转】SQL中的锁、脏读、不可重复的读及虚读
    【转】WCF扩展系列
    【转】WCF设置拦截器捕捉到request和reply消息
    关于拦截器模式的理解
    【转】netty源码分析之LengthFieldBasedFrameDecoder
    【转】使用nginx搭建高可用,高并发的wcf集群
    【转】Nginx 反向代理 负载均衡 虚拟主机配置
  • 原文地址:https://www.cnblogs.com/chengzi/p/5673877.html
Copyright © 2011-2022 走看看