容器组件
这种模式又称为“聪明组件”和“傻瓜组件”,其实名称又很多:
- 容器组件和展示组件(Container Component & Presentational Component)
- 胖组件和瘦组件
- 有状态组件和无状态组件
其实这种模式就是两个组件形成父子关系,父组件负责管理数据状态,子组件子负责展示。该模式主要是为了让一个组件的职责更少(Separation of Concerns,关注度分离原则)。
因为父组件负责管理数据状态,因此父组件是有状态组件,一般使用Class来创建;而子组件只负责展示,因此可以是纯函数,可以使用函数形式来创建。
但函数组件不能应用shouldComponentUpdata生命周期钩子,不能更有效的渲染,所以一般推荐使用class以及PureComponent来创建子组件。
class ChildComponent extends React.PureComponent {
render() {
return <div>Child Component</div>
}
}
在React v16.6.0之后的版本中,可以使用React.memo来完成相同的功能,React.memo是一个高阶组件,相比PureComponent而言,允许用户创建相同功能的函数式组件。
const ChildComponent = React,memo(props => {
return <div>Child Component</div>
})
高阶组件
在React中,“一切皆组件”,并且“组件可以是函数”。因此两者结合在一起会有一些奇妙的反应,高阶组件是其中的一个,下面的render Props是另外一个。
高阶组件是为了遵循DRY(Don`t Repeat Yourself)原则,实现组件的复用。
高阶组件本质是一个函数,接受一个或多个组件作为参数,返回另外一个新组件(这个新组件子在功能上应该比传入的组件强,因此该模式也叫增强组件模式(Ehancer Component))。
const withDoNothing = (Component) => {
const NewComponent = (props) => {
return <Component {...props} />;
}
return NewComponent;
}
几点建议
- 高阶组件应该是一个纯函数,这样可以实现多个高阶组件的链式调用;
- 高阶组件名统一以with开头,这样一看到with开头的组件就知道是一个高阶组件;
- 高阶组件在参数上应该是透明的,应该将传入高阶组件的参数原模原样的传给原组件,这样避免了参数的混乱,可以只看高阶组件的参数定义就知道传递哪些参数。
几个缺点
1.高阶组件需要处理displayName,否则debug会很痛苦;
const withExample = (Component) => {
const NewComponent = (props) => {
return <Component {...props} />;
}
NewComponent.displayName = `withExample (${Component.displayName || Component.name || 'Component' })`;
return NewComponent;
}
2.高阶组件支持嵌套调用,但应该注意,不要有过深的嵌套,否则报错时会看到超深的stack trace;
3.使用高阶组件一定要小心,不要在中间过程重复产生React组件,就像下面这样:
const Example = () => {
const EnhancedFoo = withExample(Foo);
return <EnhancedFoo />
}
render props
任何被用于告知组件需要渲染什么内容的函数prop在技术上都可以被称为“render prop”。
也就是说可以通过props传递一个函数给组件,在组件内部调用这个函数,如果这个函数返回的是React元素(也就是说这个函数本身就是一个组件),那么这就是render props模式。
使用render props模式,可以将组件应该渲染什么内容的权利交给组件调用方(父组件),从这个方面来讲,render props其实就是React世界中的“依赖注入”(Dependency Injection)。
<Auth
login={{username}} => <h1>Hello {userName}</h1>}
nologin = {() => <h1>Please login</h1>}
/>
render props和高阶组件的比较
- render props模式的应用,就是做一个React 组件,而高阶组件,虽然名为“组件”,其实只是一个产生React组件的函数;
- render props模式没有高阶组件那些缺点,但同时也没有高阶组件可链式调用的优点,不过这种模式更加灵活。
因此在实际开发过程中,建议按照这样的顺序考虑:
也就是优先考虑能不能通过普通组件完成功能,如果不能,优先考虑render props模式,最后再考虑高阶组件。