React组件开发流程——利用React构建简单的可检索产品数据表

Posted 刻刻帝丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React组件开发流程——利用React构建简单的可检索产品数据表相关的知识,希望对你有一定的参考价值。

tip:有问题或者需要大厂内推的+我脉脉哦:丛培森 ٩( ‘ω’ )و

【本文源址:http://blog.csdn.net/q1056843325/article/details/54755521 转载请添加该地址】

今天就是春节了,祝各位鸡年大吉,心想事成
感觉这两天错过了好几个亿
净往外赔钱了~马云爸爸才给了我2.08. 心塞
不过咱也算是参加过一个两亿的项目了
昨晚发现博客还增加了30+访问流量
没想到除夕夜还有这么多努力的人. 佩服 d===( ̄▽ ̄*)b
好了废话不多说


使用React构建可搜索产品数据表
是React官网上的一个demo,它不是很难
不过却能够很好的映射React的开发流程
而且把我们常用的语法基本都涉及了
可以让我们对于React有更进一步的理解
React官方传送门:Thinking in React

#UI与JSON
首先我们从我们的UI设计师那里拿到了UI模拟图和JSON-API

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

category是产品类别
price是产品价格
stocked是有无库存
name是产品名称
#拆分UI视图
首先我们要做的第一项工作就是拆分UI
把它们拆解成一个个组件,组件中还有子组件
并且赋给它们名字
这个UI可以拆分成五个组件

  1. FilterableProductTable (黄色)
    完整的产品表
  2. SearchBar (深蓝色)
    用户输入部分
  3. ProductTable (绿色)
    产品完整展示部分
  4. ProductCategoryRow (天蓝色)
    产品类别标头
  5. ProductRow (红色)
    产品信息

当然你也可以在细拆把ProductTable中的Name和Price拆出来
不过我觉得没必要搞得这么复杂
组件层次关系如下:

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

#构建静态版本
静态的版本也就是页面最初应该显示的版本
构建它不需要复杂的想法,只是代码多了点
官网上的文档是这样说的

In simpler examples, it’s usually easier to go top-down,
and on larger projects, it’s easier to go bottom-up and write tests as you build

意思就是像我们这样简单的例子中
通常由顶级层次组件向下来写更简单一些
而在大型的项目中
最佳实践是从下级层次往上写并且要做必要的测试
那在这里的demo我们就从FilterableProductTable组件开始写

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'
];
var FilterableProductTable = React.createClass(
    render: function()
        return (
            <div>
                <SearchBar/>
                <ProductTable products=this.props.products/>
            </div>
        )
    
);
var SearchBar = React.createClass(
    render: function()
        return (
            <div>
                <input type="text"/><br/>
                <input type="checkbox"/>Only show products in stock<br/><br/>
            </div>
        )
    
);
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>
                        <td><strong>Name</strong></td>
                        <td><strong>Price</strong></td>
                    </tr>
                </thead>
                <tbody>
                    rows
                </tbody>
            </table>
        )
    
);
var ProductCategoryRow = React.createClass(
    render: function()
        return (
            <tr>
                <td><strong>this.props.category</strong></td>  
            </tr>
        )
    
);
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>
        )
    
);
ReactDom.render(
    <FilterableProductTable products=PRODUCTS/>,
    document.getElementById('root')
)

很好的体现了React单向数据流的特点
将JSON数据交给父级
然后父级再讲数据传递下去
这里比较关键的代码就是ProductTable中的这部分了

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

利用了数组的形式将静态列表的组件项存储下来
使用变量lastCategory,当当前遍历的product中category与lastCategory不同时
就向数组中添加ProductCategoryRow组件

#售罄产品过滤
我们先来考虑点击那个复选框来重置是否显示售罄产品过滤
很容易的就可以想到必须要设置一个状态
这个状态就是是否只显示有库存的产品(或者不显示售罄产品)
然后为复选框绑定change事件改变状态

var FilterableProductTable = React.createClass(
    getInitialState: function()
        return 
            inStockOnly: false
        
    ,//设置初始状态:产品默认展示全部
    checkHandler: function()
        this.setState(
            inStockOnly: !this.state.inStockOnly
        );
    ,//复选框要绑定的事件处理函数:改变inStockOnly状态
    render: function()
        return (
            <div>
                <SearchBar checkHandler=this.checkHandler/> //将事件处理函数作为数据传递给子级
                <ProductTable products=this.props.products inStockOnly=this.state.inStockOnly/>
                //将状态state作为属性props传递给子级
            </div>
        )
    
);
var SearchBar = React.createClass(
    render: function()
        return (
            <div>
                <input type="text"/><br/>
                <input type="checkbox" onChange=this.props.checkHandler/>Only show products in stock<br/><br/>
                //为复选框绑定change事件处理函数
            </div>
        )
    
);
var ProductTable = React.createClass(
    render: function()
        var rows = [];
        var lastCategory = null;
        var products = this.props.inStockOnly ?
                       this.props.products.filter(function(product)
                           return product.stocked;
                       ) : this.props.products;
        //通过判断状态inStockOnly来决定是否过滤products数组
        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>
                        <td><strong>Name</strong></td>
                        <td><strong>Price</strong></td>
                    </tr>
                </thead>
                <tbody>
                    rows
                </tbody>
            </table>
        )
    
);

#关键字过滤产品
进度已经过去一大半了
剩下一个问题就是我们在输入框中输入字符时
同样需要对产品进行“过滤”
现在我们需要另外的状态——输入框字符改变
还需要一个事件处理函数来改变这个状态

var FilterableProductTable = React.createClass(
    getInitialState: function()
        return 
            inStockOnly: false,
            filterText: '' //表示输入框中字符
        
    ,
    checkHandler: function()
        this.setState(
            inStockOnly: !this.state.inStockOnly
        );
    ,
    textHandler: function(text)
        this.setState(
            filterText: text
        );
    , //输入框字符改变状态随之改变,但是还不能获取输入框中字符,所以设置一个参数test
    render: function()
        return (
            <div>
                <SearchBar checkHandler=this.checkHandler textHandler=this.textHandler/>
                //将事件处理函数作为数据传递给SearchBar组件
                <ProductTable products=this.props.products inStockOnly=this.state.inStockOnly filterText=this.state.filterText/>
                //将filterText状态传递给ProductTable组件
            </div>
        )
    
);
var SearchBar = React.createClass( 
    Handler: function()
        this.props.textHandler(this.refs.input.value);
    , //为了将获取的输入框内字符传入textHandler作为参数,外部包装一个函数
    render: function()
        return (
            <div>
                <input type="text" ref="input" onChange=this.Handler/><br/>
                // 绑定change事件处理函数
                <input type="checkbox" onChange=this.props.checkHandler/>Only show products in stock<br/><br/>
            </div>
        )
    
);
var ProductTable = React.createClass(
    render: function()
        var rows = [];
        var lastCategory = null;
        var products = this.props.products;
        var inStockOnly = this.props.inStockOnly;
        var filterText = this.props.filterText;
        products = inStockOnly ?
                   products.filter(function(product)
                       return product.stocked;
                   ) : products;
        products = filterText ?
                   products.filter(function(product)
                       return product.name.indexOf(filterText) !== -1;
                   ) : products;//通过字符限制一步过滤
        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>
                        <td><strong>Name</strong></td>
                        <td><strong>Price</strong></td>
                    </tr>
                </thead>
                <tbody>
                    rows
                </tbody>
            </table>
        )
    
);

#完整版本
完整的脚本代码如下

var React = require('react');
var ReactDom = require('react-dom');
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'
];
var FilterableProductTable = React.createClass(
    getInitialState: function()
        return 
            inStockOnly: false,
            filterText: ''
        
    ,
    checkHandler: function()
        this.setState(
            inStockOnly: !this.state.inStockOnly
        );
    ,
    textHandler: function(text)
        this.setState(
            filterText: text
        );
    ,
    render: function()
        return (
            <div>
                <SearchBar checkHandler=this.checkHandler textHandler=this.textHandler/>
                <ProductTable products=this.props.products inStockOnly=this.state.inStockOnly filterText=this.state.filterText/>
            </div>
        )
    
);
var SearchBar = React.createClass( 
    Handler: function()
        this.props.textHandler(this.refs.input.value);
    ,
    render: function()
        return (
            <div>
                <input type="text" ref="input" onChange=this.Handler/><br/>
                <input type="checkbox" onChange=this.props.checkHandler/>Only show products in stock<br/><br/>
            </div>
        )
    
);
var ProductTable = React.createClass(
    render: function()
        var rows = [];
        var lastCategory = null;
        var products = this.props.products;
        var inStockOnly = this.props.inStockOnly;
        var filterText = this.props.filterText;
        products = inStockOnly ?
                   products.filter(function(product)
                       return product.stocked;
                   ) : products;
        products = filterText ?
                   products.filter(function(product)
                       return product.name.indexOf(filterText) !== -1;
                   ) : products;
        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>
                        <td><strong>Name</strong></td>
                        <td><strong>Price</strong></td>
                    </tr>
                </thead>
                <tbody>
                    rows
                </tbody>
            </table>
        )
    
);
var ProductCategoryRow = React.createClass(
    render: function()
        return (
            <tr>
                <td><strong>this.props.category</strong></td>  
            </tr>
        )
    
);
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>
        )
    
);
ReactDom.render(
    <FilterableProductTable products=PRODUCTS/>,
    document.getElementById('root')
)

UI视图切分为组件模块
将JSON数据放入父级组件
再将数据props流入子级组件
设置状态位,然后通过事件处理函数改变状态state
state改变,触发DOM的不断渲染
这个例子诠释了React的组件化、单向数据流的特点

主页传送门

以上是关于React组件开发流程——利用React构建简单的可检索产品数据表的主要内容,如果未能解决你的问题,请参考以下文章

前端工程化实战:React 模块化开发性能优化和组件化实践

盘点| 有哪些比较新的好用的React Native 开发工具?

React16组件化+测试+全流程 实战“在线账本”项目

使用react-flow制作流程图

开源 React 组件(融合响应式设计)现已发布!

React.js入门篇——快速搭建开发环境