在使用React中,你是否会出现过一个文件的代码不少,既存在应用数据的读取和处理,又存在数据的显示,并且每一个组件还不能复用。html
首先咱们来看一个容器组件和展现组件一块儿的例子吧。react
class TodoList extends React.Component{ constructor(props){ super(props); this.state ={ todos:[] } this.fetchData = this.fetchData.bind(this); } componentDidMount(){ this.fetchData(); } fetchData(){ fetch('/api/todos').then(data =>{ this.setState({ todos:data }) }) } render(){ const {todos} = this.state; return (<div> <ul> {todos.map((item,index)=>{ return <li key={item.id}>{item.name}</li> })} </ul> </div>) } } 复制代码
你们能够看到这个例子是没有办法复用的,由于数据的请求和数据的展现都在一个组件进行,要实现组件的复用,咱们就须要将展现组件和容器组件分离出来。api
具体代码以下:数组
//展现组件 class TodoList extends React.Component{ constructor(props){ super(props); } render(){ const {todos} = this.props; return (<div> <ul> {todos.map((item,index)=>{ return <li key={item.id}>{item.name}</li> })} </ul> </div>) } //容器组件 class TodoListContainer extends React.Component{ constructor(props){ super(props); this.state = { todos:[] } this.fetchData = this.fetchData.bind(this); } componentDidMount(){ this.fetchData(); } fetchData(){ fetch('/api/todos').then(data =>{ this.setState({ todos:data }) }) } render(){ return (<div> <TodoList todos={this.state.todos} /> </div>) } } 复制代码
当咱们把组件分离成容器组件和展现组件这两类时,你会发现他们可以很方便的实现复用。性能优化
Page,Header,Sidebar,UserInfo,Listbash
UserPage, FollowersSidebar, StoryContainer, FollowedUserListmarkdown
我建议你从开始建立组件时只使用展现组件,到最后会意识到你传递了不少props到中间组件,而这些中间组件根本不会用到他们接收到的这些props,仅仅是向下传递。而当这些子组件须要更多的数据时,你须要重新配置这些中间组件。这个时候就须要引入容器组件了。使用容器组件的方式,您能够将数据和行为经过props传递给叶子组件,而没必要麻烦一些不相关的中间组件。less
这是一个重构的过程,因此不比在第一次就作对。当你尝试这种模式。在什么时候应抽取为容器组件你将会有一种直观的感受。就像您知道什么时候抽取函数同样ide
重要的是你须要明白容器组件和展现组件之间不是技术上的区别,而是目的上的区别。函数
相比之下,这里有几个相关的(但不一样的)技术区别:
有状态【Stateful】和 无状态【Stateless】:
容器组件倾向于有状态,展现组件倾向于无状态,这不是硬性规定,由于容器组件和展现组件均可以是有状态的。
类【Classes】 和 函数【Functions】:
组件能够被申明成类或函数,函数组件定义简单,可是他缺少目前仅用于类的一些功能。虽然函数组件有不少限制,可是直到如今还有人使用,是由于函数组件容易理解,建议在不须要本身的state,lifecycle hooks,或性能优化的状况下使用函数组件。这些仅适用于类组件。
//咱们将上边的展现组件改写成函数组件能够以下 function TodoList(props){ return (<div> <ul> {props.todos.map((item,index)=>{ return <li key={item.id}>{item.name}</li> })} </ul> </div>) } 复制代码
可能不少人不清楚函数组件和类组件的区别,能够去React的官网看一下函数组件和类组件
纯粹【Pure】 和 不纯粹 【Impure】:
纯粹:输入什么就输出什么,不会再其中作相应的变更。能够被定义为类或函数,能够是无状态或有状态的,纯组件的另外一个重要方面是它们不依赖props或state中的深度变更,因此他们的渲染性能能够经过在shouldComponentUpdate()钩子中进行浅层比较来优化,当前只有类能够定义shouldComponentUpdate()方法。
不论是展现组件仍是容器组件都会有上面的二分特性。在我看来,展现组件每每是没有状态的纯函数,而容器组件每每是有状态的纯类,这仅仅我的观点并不是规则。
当不重要或说很难分清时,不要把分离容器组件和展现组件当作教条, 若是你不肯定该组件是容器组件仍是展现组件是,就暂时不要分离,写成展现组件吧。
译文来源:https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0