关于React的思考

来源:互联网 发布:php缓存技术有哪些 编辑:程序博客网 时间:2024/06/06 12:37

关于React的思考

我们从一个可搜索的产品表来领会一下React的工作流程。
这是应用的完成状态JSFiddle代码地址。
这个产品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"}];

有产品分类,产品价格,是否还有库存,和产品名。

Step 1:把UI分解成组件结构

首先把整个UI分解成不同的组件,那么怎么知道哪个部分或者哪些部分作为一个组件呢?当我们写一个函数或者对象的时候会怎么做呢,答案就是单一职责原则,让一个组件做好一件事就可以了。还有就是我们可以根据数据模型来分割组件,数据模型和UI表现往往表现一致。下面是我们对产品搜索表进行的UI组件划分。

包括:

  • FilterableProductTable(orange):包含了整个应用
  • SearchBar(blue):接收用户的输入
  • ProductTable:根据用户输入显示过滤后的产品数据
  • ProductCategoryRow:显示一组产品的分类目录
  • ProductRow:每行显示一种商品
    在ProductTable中还有两个不是一个组件的单词,Name和Price,这里见仁见智,因为我们觉得它们是产品表的一部分,所以把它们归在了ProductTable里面。
    到这里组件结构就很清晰了:

  • FileterableProductTable

    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

Step2:用React创建一个静态版本

JSFiddle地址

有了组件结构之后最简单的就是构建一个静态版本,那意味着你要把你的数据硬编码在程序里,而且缺少互动,显然不是我们追求的结果。所以我们应该构建一个动态版本,增加互动和趣味性,同时也能减少你的编码量。
在静态版本里,我们通过复用组件模块和通过props属性传递数据。如果你对state属性熟悉的话,你应该知道它就是为了互动性而保留的,意思就是如果你构建的不是一个动态的应用,你最好不要请state出来,如果你对props和state还不熟悉的话,参考官方文档(自己搜吧)。
通常构建应用的方向有两种:自顶向下和自底向上。一般来说,简单的引用用自顶向下会简单一点,而复杂的应用我们建议你用自底向上的方式,这样便于你测试你写的底层组件。

Step3:在必须用state的时候再去请他

为了让你的应用UI变得互动起来,应用应该能用嗅探到数据的变化从而做出反应动作。而React中的state就是为了这个目的出生的。
为了保证你的应用精准,首先应该考虑的事情就是避免滥用state,在必须使用state的地方再去使用它。原则就是DRY:Don’t repeat yourself。那么怎么判定某个数据中必须使用state呢,很简单,问他三个问题:

  1. 这个数据是通过props从父组件传递的吗?如果是,他不是stata
  2. 这个数据不会随着时间改变?如果是,他不是state
  3. 这个数据可以通过其他的state或者props数据计算出来?如果是,他不是state

在这个查找产品的例子中,我们有这么几个数据:

  • 产品的原始列表
  • 用户在搜索框输入的文本
  • checkbox的值
  • 产品的过滤列表

那么来看看,产品的原始列表是从ReactDOM.render中从父组件中传递的,而且一般也不会改变,那他不是state。用户输入的文本和checkbox的值好像是state,因为它是用户决定的而且不能计算出来。产品的过滤列表可以通过用户输入的文本和checkbox的值计算出来,所以他不是state。所以我们有两个state数据:

  • 用户输入的搜索文本
  • 用户输入的checkbox值

Step4:让你的state数据活过来

好的,当你确定了哪些数据必须是state之后,下一件要确认的事就是哪些组件要拥有这些数据。这也是大部分新手不容易理解的地方。跟紧下面这些步骤:
对于你的应用里的每一个state数据:

  • 找出所有要基于这个数据render一些东西的组件
  • 找到这些组件的一个共同父组件
  • 这个共同父组件以及这个父组件之上的每个组件都应该拥有这个state
  • 如果你不是很清楚某个组件是否可以拥有这个state,最简单的方式就是创造一个新的组件包含这个state数据,而把这个新组件添加公共父组件(前面提到的那个)之上。

现在让我们在这个应用里使用这个策略:

  • ProductTable要根据用户搜索文本过滤产品列表,SearchBar要显示用户输入文本和复选框。
  • 这两个组件的共同父组件是FilterableProductTable
  • 理论上讲FilterableProductTable应该拥有这两个state属性

所以首先我们在FilterableProductTable中添加getInitialState方法初始化state为`{filterText:”,inStockOnly:false},然后把这两个state数据作为props传给ProductTable和SearchBar让他们做自己的render。

JSFiddle地址
你可以将getInitialState中的filterText改为’ball’运行,就可以看到过过滤后的结果了。

Step5:反向数据流

在这之前你会发现你不能在输入框中输入文字或者点击复选框,因为我们已经指定了它们的value等于一个state数据,而这个数据是从父组件中传递下来的。所以不能改变,那怎么办呢?答案是在我们输入的同时更新父组件里的state数据,子组件的state也会自动更新,那么输入框和复选框的value也会自动改变。

JSFiddle代码地址这是整个应用的完全状态。
在这之前,我们的应用的数据流向都是从父组件流向子组件进行render,现在我们来尝试另一种数据流:最深处的SearchBar数据的改变向上反映给FilterableProductTable更新state。
我们首先在FilterableProductTable中定义了一个更新state的函数,其中调用了React内置的setState函数,注意这个函数可以改变state属性,在这个应用中我们改变了过滤字符串和只显示有库存,如下:

handleUserInput: function(filterText, inStockOnly) {    this.setState({      filterText: filterText,      inStockOnly: inStockOnly    });},<SearchBar      filterText={this.state.filterText}      inStockOnly={this.state.inStockOnly}      onUserInput={this.handleUserInput}/>

然后把这个函数作为props的一个属性传给SearchBar。然后在SearchBar层面上我们给input标签设置onChange函数(注意React中给元素添加事件命名都为驼峰命名式)。如下:

handleChange: function() {    this.props.onUserInput(      this.refs.filterTextInput.value,//快速定位到ref      this.refs.inStockOnlyInput.checked    );}//render()<form>    <input      type="text"      placeholder="Search..."      value={this.props.filterText}//会根据父组件传下来的state属性动态改变。      ref="filterTextInput"      onChange={this.handleChange}    />    <p>      <input        type="checkbox"        checked={this.props.inStockOnly}        ref="inStockOnlyInput"        onChange={this.handleChange}      />      {' '}      Only show products in stock    </p>  </form>

这个onChange函数做了什么呢,调用了传递下来的handlerUserInput函数,然后在FilterableProductTable层面上完成了state的更新。
setState()会造成state的改变,而state变化的时候包含它的组件会发生自动重绘,而重绘过程是依据改变新的state数据的,这样我们就完成了动态更新,很简单,是不是?

总结一下

Step 1:把UI分解成组件结构,注意UI和数据模型趋于一致

Step2:用React创建一个静态版本,没有数据交互,像一张照片

Step3:确定必要的state数据,state不能滥用

Step4:确定包含state数据的组件,一般都包含在公共父组件中

Step5:反向数据流,根据子组件中的变化事件更新父组件中的state数据

0 0
原创粉丝点击