近期使用 React 开发过程中,随手记录了一点笔记,比较杂乱,见下文。


React 的组件生命周期如下:

  • 首先创建组件,即实例化组件,进入构造函数中
  • 在调用 render 之前,会去调用 componentWillMount 这个方法,注意,这个方法只执行一次,之后就会进入首次 render,如果需要获取首屏数据,可以在这里发起请求通过 setState 去更新视图。PS:在这里同步地 setState 与 getInitialState 是一样的,推荐使用 getInitialState 的方式设置初始状态值(http://stackoverflow.com/a/24877800)。此外,使用 ES6 的 class 语法后,这个方法可以基本废弃了。
  • 随后进入 render 方法,并构造 DOM,所以在 componentDidMount 里我们是可以拿到 DOM 的(ReactDOM.findDOMNode)
  • 当组件接收到一个新的 props 时,会去调用 componentWillReceiveProps 这个方法,但还没有真实地反映到组件中。而且在初次进入 render 之前,是不会调用这个方法的。
  • 组件接收新的 props 或者 state 时,React 允许我们调用 shouldComponentUpdate 来判断是否真的需要去重新 render。
  • componentWillUpdate 和 componentDidUpdate 分别表示组件更新前后,componentWillReceiveProps 会先于 componentWillUpdate 发生,而且组件先检测到 componentWillReceiveProps,而后可以通过自定义的 shouldComponentUpdate 方法来决定是否真的需要更新组件,如果这个时候返回 false,componentWillUpdate 和 componentDidUpdate 就都不会被调用了。
  • componentWillUnmount 这个在组件销毁的时候会被调用,可以用来做一些事后的清理工作。

关于生命周期这一块的源码参考路径:
renderers/shared/reconciler/ReactCompositeComponent.js


如果一个通用组件的形式是 <div>{this.props.children}</div> 这种,我们希望把某些 props 向下传递,如何传递呢?

可以使用 cloneElement 的方式手工设置属性到 child 组件上:

1
2
3
4
5
6
let children = React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, {info: props.info});
});
return (
<div>{children}</div>
);

对比面向对象中的类抽象概念,React 中父组件可以看作扮演的是一个抽象基类的角色,毕竟公共的外围视图部分我们是可以在父组件中定义的。而另外,对于组件内部一些共同的抽象点,可以考虑使用高阶组件(以前是使用 Mixin 来做)来实现。

React 组件中,是否一定要把所有数据都放到 redux 中管理呢?其实是没必要的。这几天的项目实践下来,从最初的所有数据都放到 store,到后面根据页面进行数据的拆分,只将平级组件或不同页面组件通信的数据放到 store 中。其实大部分数据的生命周期并没有那么长,完全可以随用随取。

举一个很简单的例子,有一个按钮是链接到元素的详情页,这种情况下可以只保留元素的基本信息(id),剩下的数据在详情页根视图的 shouldComponentUpdate 中,请求对应的数据,并且数据由详情页根视图的 state 来管理即可。


使用 React 开发的过程中,一个很容易忽视的问题就是包体积的大小。当我们引用某个组件时,很有可能直接把一整个包引进来,这无形中会增大包的体积,按需引用很重要。真正的生产线上,最好是使用压缩版加 gzip,这样可以大幅度减小体积。


在使用 fetch 的时候,异步 POST 请求参数与 jQuery 的 $.ajax 略有不同,$.ajax 请求头中数据的格式是 url-encode 的形式,而直接使用 fetch({body: JSON}); 则是 payload 的方式,二者差异在哪?对于服务器获取数据来说,又有什么区别?

HTTP 的 POST 请求中,请求头中会带一个 Content-Type 字段,会影响到后端服务器的解析。

  • application/x-www-form-urlencoded 对提交数据进行 url 编码,所以提交给服务器的请求体实际上是类似于 key=value&key=value 这种形式,jQuery 的 POST 请求默认就是使用这种形式;
  • multipart/form-data 是另外一种,使用 form 标签上传文件提交一系列表单的时候经常会使用它,在 contentType 中,它不仅仅包含 multipart/form-data,还会包含一个 boundary 用于分隔各结构,消息主体最后以 boundary— 结束。
  • 而 Request Payload 传输的则是文本流信息,使用 Node 可以用 request.pipe() 的形式把数据读取出来,注意,这种情况下不一定传输的是 key-value 的键值对信息。
  • 参考标准:http://www.ietf.org/rfc/rfc1867.txt

关于 React 开发,现在大部分情况下都是先拷贝一个已有项目,然后照着它的模式来写,基本上处于一种套逻辑的状况,这一点在公司里非常地普遍。并不是说这一点不好,但没有自己完完全全地从头到尾把整个流程搭一遍,其实很难了解构建过程中有哪些坑。此外,使用 react + redux + react-router 这一类技术栈的时候,很多情况我们其实并不了解其中的底层知识。举一个很简单的例子,在使用 react-redux 的时候,reducer 其实是不能返回直接在原始 state 修改后的结果的,如果不踩一次坑,或许我们很难明白为什么要这么搞。


视图级别的继承思考:mixin vs ES6 继承 vs 高阶组件