跟着官网的例子学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来打包,希望大家一起学习

时间: 2024-08-07 01:25:43

跟着官网的例子学Reacjs (一)FilterableProductTable的相关文章

【Flask】跟着官网做Flaskr微博

一 创建文件夹 /flaskr /static /templates static为放置css和javascript文件. templates用来放置 Jinja2 templates模板. 二 数据库模式 这个app只使用了一个数据表,使用SQLite数据库. 创建一个schema.sql文件放入到flaskr文件夹中 drop table if exists entries; create table entries ( id integer primary key autoincremen

angular2使用官网npm install下载依赖失败的处理方法

上一两个月在学习angular2,在下载依赖阶段看官网是直接自动下载的,[npm install] 就能把依赖全部弄下来.不过作为新手的我,是倒腾来倒腾去都倒不出来,因为老是报同一个错.官网也还有手动下载的,[npm run typings install],不过这个命令是报了另外一个错. 不过上面说到倒腾,其实倒腾也是有时候被你倒腾着的时候,没错,我就是倒腾的时候发现能够下载了,真神器. 这里就跟大家分享下目前来说,用 [npm]命令怎么弄依赖下来的. 这句话很重要[先手动,接着自动] (重要

社保官网查询密码重置及注册(以成都为例)

   以成都举例,首先进入成都市人力资源和社会保障局官网:http://cdhrss.chengdu.gov.cn/cdrsj/index.shtml   选择个人服务   然后选择个人社保网上经办,进入注册页面 一:没注册过,需要重新获取查询密码 如果没有注册过会有下图提示 点击注册按钮会有下图界面,这里注意社保卡查询密码,这个密码因为是随机发到你手机上的, 所以一般人也记不住,如果忘记就点击忘记社保卡查询密码重新获取 然后会有下图界面,填写身份证和姓名 接着填写你的手机号码重置即可 查询密码

4.Knockout.Js官网学习(事件绑定)

前言 click绑定在DOM元素上添加事件句柄以便元素被点击的时候执行定义的JavaScript 函数.大部分是用在button,input和连接a上,但是可以在任意元素上使用. 简单示例 <h2>ClickBind</h2> <div> You've clicked <span data-bind="text: numberOfClicks"></span> times <button data-bind="

【caffe】官网层结构译文

原文网址:http://caffe.berkeleyvision.org/tutorial/layers.html 此为Caffe官网的层讲解部分. 层讲解 要创建一个Caffe模型我们必须要在协议缓冲区(prototxt)先定义一个模型架构.Caffe的层及其参数都被定义在协议缓冲区caffe.proto. 视觉层 头文件:./include/caffe/vision_layers.hpp 通常视觉层将输入图像后会输出其他的图像,在现实世界中.一幅灰度图像有一个色彩通道(c = 1),一个RG

【Spark深入学习 -16】官网学习SparkSQL

----本节内容-------1.概览        1.1 Spark SQL        1.2 DatSets和DataFrame2.动手干活        2.1 契入点:SparkSession        2.2 创建DataFrames        2.3 非强类型结果集操作        2.4 程序化执行SQL查询        2.5 全局临时视图        2.6 创建DataSets        2.7 与RDD交互操作        2.8 聚集函数3.Sp

mysql安装文档(Linux 官网yum安装版)

mysql安装文档(官网yum安装Linx版) 创建时间:2016-12-20 文档目的 在Linux下安装mysql服务端应用. (注:本文档采用yum库安装方式安装mysql应用,本文假设您的系统中没有安装第三方发布的rpm包,如果您已经安装了第三方rpm包,请参考文中"替换第三方发布mysql"的内容) 系统环境 操作系统:centos 7 (3.10.0-229.el7.x86_64) mysql版本:mysql57-community-release-el7-9.noarch

Spring3.0官网文档学习笔记(六)--3.4.1

3.4 依赖 3.4.1 依赖注入 依赖注入两种方式:基于构造器的DI.基于setter方法的DI. 3.4.1.1 基于构造器的DI 参数是引入对象,且之前不存在父-子类关系: package x.y; public class Foo { public Foo(Bar bar, Baz baz) { // ... } } <beans> <bean id="foo" class="x.y.Foo"> <constructor-arg

弹幕视频网站的盈利模式 ——以哔哩哔哩弹幕网为例

2015 年 5 月 9 日发布的<传媒蓝皮书 :中国传媒产业发展报告 (2015)>指出,“2014 年网络广告收入首次超过电视广告”,其中贴片广告是网络广告收入的重要组成部分.而与优酷.爱奇艺等传统视频网站不同的是,以 ACG(ACG 为英文Animation.Comic.Game 的缩写,是动画.漫画.游戏的总称) 文化为主要内容的弹幕视频网站没有网络视频前的贴片广告.那么,弹幕视频网站如何实现盈利呢? 弹幕是在互联网环境下诞生的一种实时交互性评论模式,它能以滚动.停留甚至更多动作特效方