以前翻译了两篇关于Container&Presentational Component模型的文章,一篇是基础的Container和Component的定义,另一篇是进阶版,由于翻译的太烂,感受有不少错误,因此只放原文连接。segmentfault
在这里我想讨论一下我本身对这个模型的一些想法。浏览器
注:便于书写,下面统一把Container&Presentational Components模型翻译为容器&展现组件模型ide
注:下面图片中的components文件夹指的是都是Presentational Components文件夹。性能
刚接触React和这个模型的时候,我认为项目的结构应该是这样子的:spa
Containers下面一个jsx文件就表明一个页面,负责和后台交互,负责和Redux进行connect,负责传递数据给component。在Router里面放入对应页面的Container翻译
Components下面每一个jsx文件就表明页面里面全部的渲染的内容,负责渲染,和把从container拿到的数据放到页面上3d
顶多把一些基础的component分离出来,便于之后进行复用调试
但是才用两天,就知道这么搞有多么坑了。容器组件模型的目的就是复用性,可读性,可维护性,然而虽然咱们很成功的把后台交互和页面展现分离开了,可是看到这么多代码放在一块儿,我没有感受到任何复用性,可读性,可维护性,那么多代码,并且都混合了业务逻辑,你让我怎么复用,理解,维护?!component
痛定思痛,决定改一下,针对以前的问题,面向Component作出修改。基本的想法是这样子的:尽可能拆分component,避免把全部的东西都放到一个文件里面; 拆出可复用的组件,便于组件的复用;拆分逻辑复杂的模块,增长模块的可读性和可维护性;因此关键字就是“拆、拆、拆”,拆出大好前程,拆出一片蓝天...orm
因此结构成了这样...
整个代码结构复杂不少,不过主要的改变就是把基础组件分离出来(Sidebar, Form之类),每个页面也精细化。咱们能够更清晰的看出每一个文件负责的功能,同时像Sidebar, Form这些组件均可以被多个不一样的父组件调用。
固然,这不是结束,虽然上面的方法解决了咱们可读性,可复用性,可维护性,可是也只针对Component的组件,在container中,依然会有不少的代码堆积在哪里。
并且还有一个很严重的问题,先看一个代码逻辑结构图:
咱们如今的数据是经过Container来进行管理的,因此若是Images须要图片数据,那么就须要经过Container->Top->Slide->Images这样进行数据的传递,然而这些图片数据跟中间的组件没有任何关系,可是他们还必须把数据传递给下一级,就像公交车上,从后门递公交卡到前门刷同样,中间的人的心理OS实际上是:
固然代码是没有情感的,不会以为厌烦,可是因为中间每一层都须要传递数据给下层,一旦某些数据发生改变,就形成了中间层级的从新render,浪费了浏览器性能的同时,增大了调试的难度,并且接收数据的组件还要考虑“中间那些牲口们有没有动个人数据”?!
因此,为何必定要让顶级的container做为惟一的数据来源呢?
读了这篇文章就知道,Container是能够包含多个Container和Presentational Component的,因此咱们能够适当的提高一些组件成为container。若是老板一我的直接管理不少员工,绝对会乱七八糟的,这个状况下,leader这个角色就应运而生,咱们修改一下文件的结构:
如今,代码的逻辑结构就变成这样子:
做为老板的index.jsx,如今主要负责:
页面的基础配置,好比页面的title,好比页面总体内容结构的配置
页面全局的数据的获取和修改
做为leader的Top, Content,如今主要负责:
和index.jsx进行沟通,获取基础配置和数据
负责整合须要的container和component
获取和处理本身对应模块的数据,并传递给下一层级
做为presentational component的组件,就负责获取数据并进行渲染
这么作的好处是,分离了原来顶层container的繁重的任务,使代码更加清晰。同时减小了从数据源到叶子结点的层级,减小了中间层级的数量和没必要要的重复渲染。
固然,或许你会以为以前举的那个栗子,只有index.js下面有一层container,或许中间节点仍是太多。其实container里面能够包含container,根据须要,能够建立不少container在不一样的层级上。
View-Container-Presentational Component模型?这个名字是我本身编的,实际上是对上面说的结构的一个分离。我也看到过有人说Page-Module-Component模型,反正大概思路都是同样的。
其实和上面的差很少,可是做为一个大老板来讲,确定不能和一堆下级员工混在一块儿,位置看起来有点混乱不说,"客人"(好比Router)来了,还不容易认。因此,我以为应该给老板一个包间,让老板们在本身的包间中,听候客人的调遣。因此作出一点改动:
Okay,这就是个人最终方案,相比于最先的结构,这个结构更清晰,每一个模块负责的功能也更明确,代码可读性、可复用性和可维护性更高。
Container和Presentational Component的区别?
Container一般会负责和服务端的沟通,还有一些业务逻辑的处理。他们一般只负责获取数据,处理数据,处理状态,但通常不知道如何去展现页面。
Presentational Component一般不知道数据如何获取,也不知道这些数据是作什么用的,更不知道怎么去操做这些数据,他们通常只负责页面的渲染,把领导给的数据放到对应的位置。
固然一切都不是绝对的,容器组件模型只是一个指导思想,并非一个硬性的规定,你能够按照本身的须要来进行改变。并且我在上面给了两个通常,也是说明这些不是绝对的。Container固然能够负责页面的展现,老板虽然大部分负责方向和管理,但谁规定老板就不能写代码的?!一样,Component也能够负责获取数据,举个栗子,一个地图的component,或者一个天气预报的component,他们能够从固定的地方获取数据,并把数据渲染出来。
Container能够包含Presentational Component?Presentational Component是否能够包含Container?
Container能够包含Container和Component。
可是Component通常不包含Container,虽然这篇文章的做者最后改口说,Component也能够包含Container,可是我的以为应该保证component的纯净性,若是包含Container,那么就再也不纯净,或许在复用的时候,会出现误差的状况。
固然像我以前所说,一切都不是硬性规定,或许也只是由于我接触的少因此没有想到Presentational component须要包含container的状况,一切都根据本身的须要进行调整。
如何知道何时要用container,何时要用Presentational component?
通常Presentational component应该是纯净(Pure)的,也就是说父级传给他的数据不变,那么渲染出来的结果也不该该发生任何变化。因此当一个组件须要业务逻辑处理,业务数据获取,那么能够考虑使用container。若是不须要这些东西,那么考虑使用Presentational component。固然,像以前所说的地图,天气预报,按照逻辑他们也属于component,可是他们也获取数据,处理数据。
当不知道该使用container仍是Presentational component的时候,那么或许你在这个时候并不须要去决定这个问题。这种状况下,能够直接使用container来写,当你的container变得愈来愈复杂,代码量愈来愈多,逻辑愈来愈不清晰的时候,你就能够考虑分离处更多的container和Presentational component来。
若是这篇文章指导的方向有错误,里面有不少的问题,该怎么办?
欢迎指出和讨论,一切问题都会认真回答,虚心接受。
若是我也答不出来,那我会看成没看到...