详解展现组件和容器组件的区别和应用

在使用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>)
    }
}

复制代码

当咱们把组件分离成容器组件和展现组件这两类时,你会发现他们可以很方便的实现复用。性能优化

展现组件(Presentational Component)

  1. 关注页面的展现效果(外观)
  2. 内部能够包含展现组件和容器组件,一般会包含一些本身的DOM标记和样式(style)
  3. 一般容许经过this.props.children方式来包含其余组件。
  4. 对应用程序的其余部分没有依赖关系,例如Flux操做或store。
  5. 不用关心数据是怎么加载和变更的。
  6. 只能经过props的方式接收数据和进行回调(callback)操做。
  7. 不多拥有本身的状态,即便有也是用于展现UI状态的。
  8. 会被写成函数式组件除非该组件须要本身的状态,生命周期或者作一些性能优化。
Example:

Page,Header,Sidebar,UserInfo,Listbash

容器组件(Container Component)

  1. 关注应用的是如何工做的
  2. 内部能够包含容器组件和展现组件,但一般没有任何本身的DOM标记,除了一些包装divs,而且从不具备任何样式。
  3. 提供数据和行为给其余的展现组件或容器组件。
  4. 调用Flux操做并将它们做为回调函数提供给展现组件。
  5. 每每是有状态的,由于它们倾向于做为数据源
  6. 一般使用高阶组件生成,例如React Redux的connect(),Relay的createContainer()或Flux Utils的Container.create(),而不是手工编写。
Example:

UserPage, FollowersSidebar, StoryContainer, FollowedUserListmarkdown

优势(benifit)

  1. 展现和容器组件更好的分离,有助于更好的理解应用和UI
  2. 重用性高,展现组件能够用于多个不一样数据源。
  3. 展现组件就是你的调色板,能够把他们放到单独的页面,在不影响应用程序的状况下,让设计师调整UI。
  4. 这迫使您提取诸如侧边栏,页面,上下文菜单等“布局组件”并使用this.props.children,而不是在多个容器组件中复制相同的标记和布局。

什么时候引入容器组件

我建议你从开始建立组件时只使用展现组件,到最后会意识到你传递了不少props到中间组件,而这些中间组件根本不会用到他们接收到的这些props,仅仅是向下传递。而当这些子组件须要更多的数据时,你须要重新配置这些中间组件。这个时候就须要引入容器组件了。使用容器组件的方式,您能够将数据和行为经过props传递给叶子组件,而没必要麻烦一些不相关的中间组件。less

这是一个重构的过程,因此不比在第一次就作对。当你尝试这种模式。在什么时候应抽取为容器组件你将会有一种直观的感受。就像您知道什么时候抽取函数同样ide

二分法

重要的是你须要明白容器组件和展现组件之间不是技术上的区别,而是目的上的区别。函数

相比之下,这里有几个相关的(但不一样的)技术区别:

  1. 有状态【Stateful】和 无状态【Stateless】:

    容器组件倾向于有状态,展现组件倾向于无状态,这不是硬性规定,由于容器组件和展现组件均可以是有状态的。

  2. 类【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的官网看一下函数组件和类组件

  1. 纯粹【Pure】 和 不纯粹 【Impure】:

    纯粹:输入什么就输出什么,不会再其中作相应的变更。能够被定义为类或函数,能够是无状态或有状态的,纯组件的另外一个重要方面是它们不依赖props或state中的深度变更,因此他们的渲染性能能够经过在shouldComponentUpdate()钩子中进行浅层比较来优化,当前只有类能够定义shouldComponentUpdate()方法。

不论是展现组件仍是容器组件都会有上面的二分特性。在我看来,展现组件每每是没有状态的纯函数,而容器组件每每是有状态的纯类,这仅仅我的观点并不是规则。

当不重要或说很难分清时,不要把分离容器组件和展现组件当作教条, 若是你不肯定该组件是容器组件仍是展现组件是,就暂时不要分离,写成展现组件吧。

译文来源:https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

相关文章
相关标签/搜索