A Compact React Cookbook

前端之家收集整理的这篇文章主要介绍了A Compact React Cookbook前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这是一本非常 campact 的 React 煮书,收集了在实践 React 时的一些问题和解决方法

1Why not 2 way binding/为毛不用双向绑定

解释这个问题我们需要先看什么是双向绑定,什么是单向绑定

1.1双向绑定

也就是dom 上的 value 与 controller 或者 view controller 上的绑定,值保持一致。

1.2单向绑定

dom 上的值来源于 controller,但是 dom 上的值改变不会改变 controller 上的值。

1.3双向有什么不好1

  • perfomance
  • 我们真的需要吗?实际上有多少值是真的需要双向绑的
  • 到底谁动了我的值?too many sources of truth

1.4单向有什么好

  • 只有一个 source of truth,代码好 reason about
  • 更快
  • 需要的时候自己绑一把,也并不是多麻烦的事
var TwoWayBindingInput = React.createClass({
  getInitialState: function() {
    return {message: 'Hello!'};
  },handleChange: function(event) {
    this.setState({message: event.target.value}); // <= (setstate)
  },205)">render: message = this.state.message;
    return <input type="text" value={message} onChange={this.handleChange} />; <= (value)
  }
});

注意看这个双向绑定,第value行是单向绑定值messageinput元素上,第setstate行是把input元素的值绑定回来,但是注意看这里绑定回来需要通过setState来完成,这就保证了 React Component 的 source of truth 还是只有 state。

2What's Virtual DOM,why should we care / 为毛要用 Vitual Dom

2.1以前是如何操作 DOM 的 (Mutable)

  1. query 到 DOM 上一个元素
  2. 改吧改吧

2.2Virtual DOM (Immutable)

  1. 想好要往 DOM 上放什么东西
  2. 把它给 Virtual DOM
  3. Virtual DOM 决定哪些应该修改 DOM 哪些不用

    为什么说前者是 Mutable 后者是 Immutable,这是相对你的业务逻辑来说的。

DOM 本身是 Mutable 的东西,把它柔和到你的业务上给你的逻辑加上了不少 mutable 的因素,而 Virtual DOM 成功的屏蔽掉了 mutable 的 DOM,每次 render 的 Component 其实都是新的,并不是以前 Component 的修改

所以使用 Virutal DOM

  • 容易 reason about, 因为 immutable
  • 把紧耦合编程了高内聚

3Why Immutable / 为毛要不可变

Immutable 是函数式的概念之一,一旦创建出来之后,就不能再改变。因此,当你想对其做修改,就得弄一个新的。

好奇的同学要问了,但是 React 看起来是面向对象的啊。createClassstate函数式有状态和 class 吗?

If a tree falls in a forest and no one is around to hear it,does it make a sound?2

首先,函数式和面向对象并不冲突,两种编程范式分别有各自的方式解决问题。

其次:

3.1状态

如果状态只存在于 Component 中又并没有影响任何人,它还是状态吗?

ClojureScript 的 React 库 om,只有一个 app 级别的 state。因此所有的 component,其实并无状态。

https://youtu.be/5yHFTN-_mOo

3.2Class

想象一下使用一个 React Component 的时候

<AFancyHelloWord message="Good News Everyone!"/>

来想象一下

  1. 尖括号<往右移
  2. 尖括号变成圆括号
  3. 里面再加个大括号
  4. 等号变冒号
AFancyHelloWord({message:"Good News Everyone!"})

./images/futurama_August_26__2015_at_0617AM.gifok,如果把每个 Component 看成一个函数,为了我们的代码更好 reason about 而且更 loose couple,我们应该尽量要消除每一个 Component 的状态。 这样在 Component 的树中,我们可以随意切换 Component,以 Star Wars 为例,Anakin 有两样东西,Luke 和光剑:

当 Anakin 变成 Darth Vader,光剑的颜色变红时,Darth Vadar 有 Luke 和 红色光剑。

实际上我们需要尽量减少 Component 中的状态,而且对着少数的状态,由于他们是我们的 source of truth,并不希望他是 mutable 的,这样我很难知道谁动了我的 source of truth。

3.3让你的数据结构 immutable 的工具们

@H_404_283@ Immutablility helper

这是 react addon 中自带的工具,如果你并不想完整的 Immutable 数据结构,这个工具可以帮助 copy 一份来做改动

update = require('react-addons-update');
inc = x=>x+1
fancyPropsForChild=update(this.state,{
    x: {y: {z: {$set: 7}}},a: {b: {$push: [9]}},h: {$merge: {i: "j"}},e: {$apply: inc}
});

mori

更为彻底的选择是,使用 ClojureScript 的 Immutable 数据结构。benchmark 要比 facebook 的 Immutable.js 好上许多,但是使用上跟 ClojureScript 一致, 用惯JavaScript的人可能不太能习惯,alternative 是使用我 fork 的 mori 版本conjs

Immutable.js

facebook 实现的 immutable 数据结构,使用上比较符合 JavaScript 习惯一些, 不过跑分低一些。

4How to do Unit test React project / 如何单元测试

4.1Jest

总的来说,jest 的测试理念解决了非常多的前端测试的棘手问题,我做过一个关于 jest 的 session, 文章这里文章可能写得有点早,非常知道高兴的是终于支持最新的 nodejs 了,而且 重要的是 facebook 使用 jest 测试 react,有一些非常方便的 mock component 的方法

recap 一下主要是

  • automock/ manual mock
  • jsdom
  • 并行测试

4.2jasmine

jasmine 只是一个引擎,jest 也是用 jasmine 作为引擎。但是如果由于某种原因你不想用 jest 的话,可能你需要花更多的 effort 在:

  • mock (rewire.js)
  • runner (karma)
  • headless browser for ci(phantomjs)

所以并不推荐花这么大 effort 去撘一个 jasmine 的测试环境,关键还会有一系列的问题

  • phantomjs 怪怪的 issue
  • karma 复杂的配置
  • rewire 也有一些坑

4.3mocha

没试过用来测 React,不过 mocha 比 jasmine 好的一点是本身就可以跑在 node 上,使用 sinon(mock) 和 should.js(assert) 是个非常强大的一套测试工具。

5Modular and Components

5.1browserify

简单的 modular bundler,推荐, 因为职责单一的工具更不容易遇到奇怪的问题。

使用 browserify 使用babel transformer就可以把所有的 component 以 node 的方式模块化的组织,最后 bundle 成一个 js 文件

5.2webpack

以 grunt 的方式 browserify 你的代码,非常强大的 bundler。但是个人并不喜欢 grunt,karma,webpack 这种基于配置的工具,原因很简单,配置不是代码!配置不是代码!配置不是代码! 配对了当然简单,但是配错了怎么办,没法 debug。

虽然不喜欢,我还是要告诉你怎么用,就这么一行配置就好了

module: {
  loaders: [
    { test: /\.jsx?$/,exclude: /node_modules/,loader: "babel-loader"}
  ]
}

6How should I thinking in react way / 如何以 React 的方式解决问题

要以 react 的方式思考,其实跟思考 HTML 差不多http://facebook.github.io/react/docs/thinking-in-react.html

7What about Data Fetching / 只有 V 的话,数据 M 呢

7.1justrest

简单,rest 请求回来一个 Promise,你还可以用when获得更多的 promise 和 monad 用法

无需 model 在 componentDidMount 发出 rest 请求,then 直接扔给 setState。最多 setState 前加些 map filter 把数据改改格式。

7.2relay/graphql

官方 data fetching 解决方案。

比起由 component 去发请求,再转换数据格式。relay/graphql 的思想是有 component 定义数据形状,由 relay 去发请求,有 graphql server 跟去根据定义返回相应形状的数据。

所以,对,会多一层 server layer。

view 层简单了,graphql 要做的事情却不少。

7.3falcor

netflix 的简单版的 graphql可以参考我的todo falcor思想大致相似,但是更为简单一些,没有什么 QL,schema 之类的

8What about Router / router 怎么办

建议使用 isomorphic router,就是 browser 与 node 都可以用的 router

8.1direactor

非常轻量级的通用 router,并不是专门为 react 准备的,但是 router 而已,为毛要跟 component 耦合。

client side

routes = {
  '/author': ()=>React.render(<Author/>,domNode),'/author/:id': (id)=>React.render(<Auther id={id}/>,domNode)
};
router = Router(routes);
router.init();

server side

只需要调用 router.dispatch 就好了,而且 server 端的 react 需要renderToString

router = new director.http.Router({
  '/author': {
    get: function(){
      this.res.end(React.renderToString(<Author/>))
    }
  }
});
server = http.createServer(function (req,res) {
  router.dispatch(req,res,err) {
    res.writeHead(200,{ 'Content-Type': 'text/html' })
    if (err) {
      res.writeHead(404);
      res.end();
    }
  });
});

8.2react router

非常非轻量级的 router,而且只能给 react component用。

概念上就是使用 Route 把你的 Component 包起来,让 router 决定到底哪个 componet 上

render((
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About}/>
      <Route path="users" component={Users}>
        <Route path="/user/:userId" component={User}/>
      </Route>
      <Route path="*" component={NoMatch}/>
    </Route>
  </Router>
),document.body)

9How to communicate between two components that don't have a parent-child relationship3/ 不是父子关系的 component 怎么交互

对于这个问题,我的问题是

如果不是父子关系或者兄弟或者伯父侄女,真的需要交互吗?

如果是在同一颗树上,那么一定能找到一个共同的 parent,把 parent 的回调传进来就好了

如果不在同一颗树上,你可能需要一个全局的一些东西

9.1event

使用随便一种 event emitter,比如backbon events。 在一个 componnet 中 trigger,另一个 component subscribe

9.2flux

flux 只是一个架构思想,你可以用任何自己喜欢的方式实现 其实跟 event emitter 差不多,只是针对和管理 state

dispatcher

作为action 的分发工作,决定哪些 action 引起哪些 store 的变化

store

状态与逻辑

9.3router

使用 router 传递信息也是可以的

9.4应用级别 state

跟 om 一样,全局应用级别 state

@H_502_692@ 10When should I use "key" / 什么时候该用 key

只有当出现一串一样的元素的时候,这个时候 Virtual DOM 去 reconciliate(搞) DOM 的时候会傻傻分不清楚。

别的时候不要用 key,key 已经出现在 virtual dom diff/reconciliation 的阶段,效率要更低于 shouldComponentUpdate,所以尽量通过 shouldComponentUpdate 来决定是否要 render component。

官网文档的这个例子

renderA: <div><span>first</span></div>
renderB: <div><span>second</span><span>first</span></div>
=> [replaceAttribute textContent 'second'],[insertNode <span>first</span>]

其实是往第一个位置插入了一个 span,但是会被 diff 成

  • 替换内容 first 到 second
  • 插入内容为 first 的 span

    不光是这样会更慢的问题,如果你在 first 上绑有事件的话,重新 render 后因为是 replace 了内容,因此这是原来的事件会变成 second 的事件,这样就完全错乱了。

11What's these Warnings / 这些黄黄的是神马

黄黄的东西(除了小黄人)请一定要除掉!

所有 react 的 warning 描述都非常详细,请一定务必要除掉。

12How to Profile Component Perfomance / 如何提升效率

当然不是咖啡!

12.2PureRenderMixin

当你的 props 和 state 都是 immutable 的时候…

PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
  mixins: [PureRenderMixin],139)">return <div className={this.props.className}>foo</div>;
  }
});

12.3shouldComponentUpdate

可以通过这个方法对于 component 到底什么情况下应该重新 render 调优

所有图片来源于 giphy.com,copyright @Futurama

Author: Jichao Ouyang

Modified: 2015-11-16 Mon 00:39

Generated by:Emacs24.5.1 (Orgmode 8.3.2)

<Publish> with _(:з」∠)_ byOrgPress

猜你在找的React相关文章