在我们的看来,React是使用js创建大型快速网站应用的首要方法。它在Facebook和Instagram的使用已经为我们展现了它自己。

React的一个很好的地方就在于当你创建应用的时候它使你思考如何创建。在这篇文档里,我们会带着你使用React创建一个查询产品数据表的流程。

以一个仿制品开始

想象我们已经有了一个JSON接口和一个设计师设计的仿制品。它的样子就像这样:

我们的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"}
];

步骤1:将UI分解成组件

首先你将要做的就是在每一个组件周围画上方框并且给它们命名。如果你和设计师一起工作,他们也许已经做了这件事,所以和他们聊一聊。他们的photoshop图层的名字也许就可以作为你的React组件的名字。

但是你如何知道它自己的组件是什么?就使用你是否需要创建一个新的函数或者对象来决定。一个类似的手法就是单个功能原则,也就是说,理想情况下一个组件应该只做一件事。如果它功能不断丰富,它应该被分解成更小的子组件。

只要你经常给用户显示JSON数据模型,你会发现如果你的数据模型是正确建立的,你的UI会被很好的映射。那是因为UI和数据模型趋于依附于同样的信息体系,这就意味着将UI分离成组件通常是很容易的。把UI分裂成一个个组件就意味着每一个组件就对应你的一部分数据模型。

你可以看到这里我们有5个组件在我们的应用里。我们已经将每一个组件所代表的数据用斜体表示。

  1. FilterableProductTable(橙色):包含整个例子
  2. SearchBar(蓝色):接受所有用户输入
  3. ProductTable(绿色):基于用户输入显示和过滤数据
  4. ProductCategoryRow(蓝绿色):显示每个category的标题
  5. ProductRow(红色):每一个Product显示一行

如果你看着ProductTable,你就会看到表标题(包含“Name”和“Price”标签)并没有作为一个组件。这是个人喜好问题,选择哪种方式目前还存在争议。对于这个例子,我们把表标题作为ProductTable组件的一部分因为因为这是ProductTable组件的责任,它需要渲染数据。然而,如果这个标题变得复杂了(也就是如果我们添加了分类排序的功能),那么它就会作为单独的ProductTableHeader组件。

现在我们已经在原型图里确认了我们的组件,让我们将它们安排成一个层级结构。这样很简单。在其他组件中出现的组件应该作为一个子节点出现在层级里。

步骤2:创建一个静态版本

在CodePen里试一试

现在你的组件在层级里了,现在是时候完成这个应用了。最简单的方式就是创建一个静态版本包含你的数据模型以及渲染UI界面但是没有交互性。最好使这些流程之间分离解耦因为创建一个静态版本更多的是需要写代码而不太需要逻辑思考,而添加交互需要许多逻辑思考不需要太多代码。我们来看看为什么。

创建一个应用的静态版本来渲染你的数据模型,你需要创建可以重用其他组件并且使用props传递数据的组件。props是一种从父组件传递数据到子组件的方法。如果你比较熟悉state的概念,请不要使用state来创建这个静态版本。state只能预留给交互的,也就是随时间的变化来改变数据。因为现在只是做一个静态版本,所以你不需要state。

你可以自顶向下或者自底向上。就是说,你要么从层级顶端来创建组件(也就是从FilterableProductTable组件开始)要么从最底端的组件开始(ProductRow组件)。在简单的例子里,通常自顶向下比较简单,并且项目越大,自底向上就越简单还可以边写边测试。

在这一步的最后,你会有一个渲染你的数据模型的可重用组件库。这些组件将只有render()方法因为这是一个静态的版本。在层级顶端的组件(FilterableProductTable)会把数据模型作为props传入。如果你改变了基本数据模型并且重新调用了ReactDOM.render(),UI就会更新。这样可以很清楚地看到UI是怎么更新的并且从哪里发生变化因为没有什么复杂的东西。React的单向数据流(也叫单向绑定)让所有东西模块化并且高效。

参考React文档如果你在执行这一步的时候需要帮助。

一个小插曲:props vs state

在React中有两种类型的“模型”数据:props和state。理解他们两个之间的区别很重要;读一读文档如果你不确定他们的区别。

步骤3:确认UI state的最小限度(但完整的)表示

想让你的UI拥有交互性,你需要能够触发你的基础数据模型的变化。React可以依靠state完成这点。

想要正确建立你的应用,你首先需要思考你的应用需要的最小限度的可变的state。关键就是DRY:不要重复你自己。想出应用需要的state绝对最小限度的表示并且计算所有你需要的请求。举个例子,如果你在创建一个TODO列表,只要保存TODO列表里的数据到一个数组里;不要为了列出的数目保存一个单独的state变量。当你想要渲染TODO时,只需要获取TODO数组的长度即可。

想一下在例子应用里所有数据。我们有:

  • 最初的产品列表
  • 用户输入的搜搜文本
  • 选择框的值
  • 过滤后的产品列表

让我们仔细检查每一个数据找出哪一个是state。对每一个数据思考三个问题:

  1. 它是否从父组件来并通过props传递?如果是,它也许不是state。
  2. 是否随时间变化它依然不改变?如果是,它也许不是state。
  3. 你是否能基于组件里其他state或者props计算出它?如果是,它不是state。

原始的产品列表作为props传递,所以他们不是state。搜索文本和选择框当它们随时间改变而且不能通过其他值计算出来,它们看起来像是state。最后,过滤后的产品列表不是state因为联合原始的列表还有搜索文本和选择框的值就可以计算出过滤后的产品列表的值。

所以,最终,state就是:

  • 用户输入的搜索文本
  • 选择框的值

步骤4:确认state应该位于哪里

在CodePen里试一试

现在我们已经确认了最小限度的state。下一步,我们需要确认哪一个组件会改变或者拥有这个state。

记住:React是单向数据流。也许不能很快确定哪一个组件拥有state。这一步对于新手来说往往是最具挑战性的部分,所以请跟随以下步骤来解决:

对于应用里每一个state:

  • 确认每一个基于state渲染UI的组件
  • 找到一个共同的组件拥有者(层级中在所有组件之上的单个组件并且需要state)
  • 要么是共同拥有者要么是另外一个更高位置的组件拥有state
  • 如果你找不到拥有state的那个组件,那就新创建一个组件来拥有state并且把它添加到在共同拥有者之上的层级的某处

让我们对我们的应用使用这个策略:

  • ProductTable需要基于state过滤产品列表,SearchBar需要显示搜索文本和选择框状态
  • 共同拥有者组件是FilterableProductTable
  • 搜索文本和选择框值应该在FilterableProductTable组件中

酷,我们已经确认了我们的state存在于FilterableProductTable组件中。首先,添加一个实例属性this.state={filterText: '', inStockOnly: false}到FilterableProductTable组件的构造函数constructor里反映出state的初始值。然后,给ProductTable组件和SearchBar组件传递filterText和inStockOnly作为一个prop来传递。最后,使用这些props去过滤ProductTable里的行并且在SearchBar的表单域里设置值。

现在你可以看看你的应用会怎样运行:设置filterText为“ball”然后刷新应用。你会看到数据表会正确地刷新。

步骤5:添加相反的数据流

在CodePen里试一试

到目前为止,我们创建了一个能够通过利用props和state从层级自顶向下传递的函数正确渲染UI的应用。现在是时候支持另外一种数据流了:在底层中的表单组件需要在FilterableProductTable组件里更新state。

React使得这种数据流很明白的让你理解程序如果工作,但是它比传统的双向绑定需要更多的代码。

在现在的例子中如果你试图输入或选中选择框,你会发现React忽略了你的输入。这是故意的,我们已经设置input的value属性总是和FilterableProductTable组件传递过来的state值一样。

来思考我们想达到一种什么效果。我们想要确保无论用户怎样修改表单,我们都会更新state来反映用户输入。组件应该只更新自己的state,FilterableProductTable组件会传递回调函数给SearchBar组件无论何时state应该被更新的时候回调函数就会被调用。我们可以在input上使用onChange事件来获取通知。FilterableProductTable组件传递的回调函数会去调用setState(),然后应用会被更新。

虽然这些听起来很复杂,但是只是几行代码而已。而且数据在应用中的流动是很简单明确的。

就这些了

希望如此,这个文档给你一些思路关于怎么使用React创建组件和应用。虽然也许它比你以前的代码量大,但是记住代码的阅读总是比写代码重要,并且模块化的代码很简单明确。当你开始创建大量的组件库的时候,你会感激这种模块化和简单明确,而且通过代码重用,你的代码量会开始减少。:)

React文档(十三)思考React的更多相关文章

  1. React文档(二十四)高阶组件

    高阶组件(HOC)是React里的高级技术为了应对重用组件的逻辑.HOCs本质上不是React API的一部分.它是从React的组合性质中显露出来的模式. 具体来说,一个高阶组件就是一个获取一个组件 ...

  2. react文档demo实现输入展示搜索结果列表

    文档页面地址:https://doc.react-china.org/docs/thinking-in-react.html 该文档只给了具体实现思路,下面是我实现的代码. 初学react,如果有写的 ...

  3. React文档(一)安装

    React是一个灵活的可以用于各种不同项目的框架,你可以用它来写新应用,你也可以逐步将它引进已有的代码库而不用重写整个项目. 试用React 如果你想玩一玩React,那么就去CodePen上试一试. ...

  4. React文档(十)表单

    HTML表单元素和 React里的其他DOM元素有些不同,因为它们会保留一些内部的状态.举个例子,这个普通的表单接受唯一的name值: <form> <label> Name: ...

  5. React文档(四)渲染元素

    元素是React应用的最小单位. 一个React元素描述了你在屏幕上所看到的东西: const element = <h1>Hello, world</h1>; 和浏览器页面中 ...

  6. React文档(二)Hello World

    开始学习React最简单的实践就是去试一试CodePen上面的Hello World程序.你不需要安装任何东西,只要新开一个标签页打开例子依照原例操作即可.如果你更喜欢在本地开发,那么来看看安装的介绍 ...

  7. 关于CSS自文档的思考_css声明式语言式代码注释

    obert C. Martin写的<Clean Code>是我读过的最好的编程书籍之一,若没有读过,推荐你将它加入书单. 注释就意味着代码无法自说明 —— Robert C. Martin ...

  8. React文档(二十三)Web Components

    React和web components是为了解决不同问题而创立的.web components为可重用组件提供了健壮的封装,而React提供了声明式的库来保持DOM和数据同步.这两点是互相补充的.作 ...

  9. React文档(十六)refs和DOM

    Refs 提供了一种方式,用于访问在 render 方法中创建的 DOM 节点或 React 元素. 在标准的React数据流中,props是使得父组件和子组件之间交互的唯一方式.你通过props重新 ...

随机推荐

  1. 005-mac下Java开发工具安装,idea,maven,git,node

    1.idea 官网下载:https://www.jetbrains.com/idea/download/#section=mac 1.1.双击安装即可. 1.2.打开程序,激活,网络搜索lanyu 1 ...

  2. python基础(15)-socket网络编程&socketserver

    socket 参数及方法说明 初始化参数 sk = socket.socket(参数1,参数2,参数3) 参数1:地址簇 socket.AF_INET IPv4(默认) socket.AF_INET6 ...

  3. 20175211 2018-2019-2 《Java程序设计》第四周学习总结

    目录 教材学习内容总结 第五章 子类与继承 教材学习中的问题和解决过程 代码调试中的问题和解决过程 代码托管 上周考试错题总结 其他(感悟.思考等,可选) 学习进度条 参考资料 教材学习内容总结 第五 ...

  4. 查询oracle数据字典,并对应出hive的数据类型

    SQL开始 select t2.owner||'.'||t2.TABLE_NAME 源表名, 'dl_{0}_seq.'||'tt_{1}_'||lower(t2.table_name) hive表名 ...

  5. 在 CentOS7 上安装 Zookeeper服务

    1.创建 /usr/local/services/zookeeper 文件夹: mkdir -p /usr/local/services/zookeeper 2.进入到 /usr/local/serv ...

  6. Java Hello World源代码notepad++版

    Notepad++中写Java Hello World代码并运行,步骤如下: 1. 在E:\CodeDemo\Java文件夹下(你也可以选择自己的文件夹)新建一个txt文本文件. 如果没有NotePa ...

  7. flask_mail发送163邮件,报553错误的原因

    最近在练习用flask_mail发送163邮件时报错: reply: '553 authentication is required,163 smtp9,DcCowAD3eEQZ561caRiaBA- ...

  8. 单源最短路——Dijkstara算法

    算法基本思想:每次找到离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径. 1.将所有的顶点分为两个部分:已知最短路程的顶点集合P和未知最短路径的顶点集合Q 2.设置 ...

  9. 【python】python2.x中的除法

    在生信分析中有许多时候我们需要用到除法,在经历无数次break out 之后我终于发现原来python 2.x中只有整除,而没有浮点除法,这就是没有基础的弊病. 那么如何在python 2.x中运用除 ...

  10. 绘制COCO数据集结果

    import os import time import datetime import mmcv import cv2 as cv import json import numpy as np im ...