Peter 注:Dan 的这篇文章对提升 React 代码开发效率有这关键性的作用,推荐每一个 React 开发者看一看。原文地址
写React应用时,我发现了一种简单而有效的模式。如果你也写过一阵子React,或许你也已经发现它了。对于这种模式,这篇文章讲得不错,不过我还想再补充几点。
如果把组件 分为两类,对组件的复用和理解会更容易一些。我这两类组件称为 展示组件和容器组件。也有叫“胖的&瘦的”、“聪明的&笨的”、“包含状态的的&纯的”、“屏幕( screen )& 组件( Components)”的等等说法,这些说法并不完全一致,但核心理念大概相同。
this.props.children
包含组件connect()
,Relay的createContainer()
或者 Flux Utils的 Container.create()
等)为了让这种区分更加明显,我会把这两类组件放到不同的文件夹里。
请注意,组件并不一定需要生成DOM。它们只需要提供 UI 组成部分之间的分界。
好好利用这一点。
在刚开始写APP的时候,我建议你只写展示组件。先就这么写着,总会有一个时刻,你将注意到,有太多的属性需要传递给中间层的组件。有些组件根本用不上这些属性,传给它们的目的,仅仅是为了能继续向下传递属性。而且,当子组件需要更多的数据时,你不得不重写中间层的组件。当你意识到这些时,就是引入容器组件的好时机。通过使用容器组件,无需途经组件树中其他无关的组件,就可以直接将数据和方法属性传给末端的叶子组件中。
这种重构的过程是渐进的,别想着一步到位。随着你对这种模式日复一日地练习,对于何时使用容器组件,你会慢慢培养出一种直觉。这种感觉就像你知道啥时候应该抽象出函数一样。我在蛋头网(egghead)上的免费系列课程也于此会有所帮助。
需要注意的是,展示组件 和 容器组件 之间的区别,并非是技术上的,而是在用途上的。理解这一点很重要。
作为对比,这里列举一些相关技术:
有状态和无状态。有的组件使用 React 的 setState() 方法,有的组件则不用。尽管容器组件多是有状态的,展示组件多是无状态的,但是这并非硬性规定。展示组件也可以是有状态的,容器组件也可以是无状态的。
类和函数。 从 React 0.14 开始 ,组件既可以声明为类,也可以声明为函数。虽然函数式组件更容易定义,但是它们缺乏某些当前只有类组件才有的功能。在未来,这些限制可能会渐渐消失,但是目前确实是存在的。因为函数式组件更容易理解,我建议你一般用函数式组件就好,除非你需要状态、生命周期钩子或性能优化等目前类组件独有的功能。
纯和不纯。给定相同的属性(props)和状态,就能返回相同的结果,那么人们就会把该组件叫纯组件。纯组件既可以被定义为类,也可以被定义为函数,既可以是有状态,也可以是无状态的。纯组件的另一个重要特征是,它们不会依赖于属性(props) 或者状态的深层变化(deep mutations),所以它们的渲染性能可以在 shouldComponentUpdate() 钩子中通过 shallow comparison 来优化。目前只有类可以定义 shouldComponentUpdate() ,这一点以后可能变。
不论是展示组件,还是容器组件,都可能是上面所列举的任意一种。以我的经验看,展示组件多是无状态的纯函数,而容器组件多是有状态的纯类。不过,这并非规定,而是经验之谈。我确实见过完全相反,但在特定条件下成立的例子。
别把展示组件/容器组件的这种分类方法视作教条。有时候其实无所谓,有时候又难以分辨。如果你对某个组件属于展示组件还是容器组件举棋不定,别急,或许还没到下结论的时候。
Michael Chan的这一篇真的说到点子上了。