关于React的Container&Presentational Component模型结构分析
之前翻译了两篇关于Container&Presentational Component模型的文章,一篇是基础的Container和Component的定义,另外一篇是进阶版,因为翻译的太烂,感觉有很多错误,所以只放原文链接。
在这里我想讨论一下我自己对这个模型的一些想法。
注:便于书写,下面统一把Container&Presentational Components模型翻译为容器&展示组件模型
注:下面图片中的components文件夹指的是都是Presentational Components文件夹。
基于容器&展示组件模型的目录结构
Round 1:
刚接触React和这个模型的时候,我认为项目的结构应该是这样子的:
Containers下面一个jsx文件就代表一个页面,负责和后台交互,负责和Redux进行connect,负责传递数据给component。在Router里面放入对应页面的Container
Components下面每个jsx文件就代表页面里面所有的渲染的内容,负责渲染,和把从container拿到的数据放到页面上
顶多把一些基础的component分离出来,便于以后进行复用
可是才用两天,就知道这么搞有多么坑了。容器组件模型的目的就是复用性,可读性,可维护性,然而虽然我们很成功的把后台交互和页面展示分离开了,但是看到这么多代码放在一起,我没有感觉到任何复用性,可读性,可维护性,那么多代码,而且都混合了业务逻辑,你让我怎么复用,理解,维护?!
Round 2:
痛定思痛,决定改一下,针对之前的问题,面向Component做出修改。基本的想法是这样子的:尽量拆分component,避免把所有的东西都放到一个文件里面; 拆出可复用的组件,便于组件的复用;拆分逻辑复杂的模块,增加模块的可读性和可维护性;所以关键字就是“拆、拆、拆”,拆出大好前程,拆出一片蓝天...
所以结构成了这样...
整个代码结构复杂很多,不过主要的改变就是把基础组件分离出来(Sidebar, Form之类),每一个页面也精细化。我们可以更清晰的看出每个文件负责的功能,同时像Sidebar, Form这些组件都可以被多个不同的父组件调用。
当然,这不是结束,虽然上面的方法解决了我们可读性,可复用性,可维护性,但是也只针对Component的组件,在container中,依然会有很多的代码堆积在哪里。
而且还有一个很严重的问题,先看一个代码逻辑结构图:
我们现在的数据是通过Container来进行管理的,所以如果Images需要图片数据,那么就需要通过Container->Top->Slide->Images这样进行数据的传递,然而这些图片数据跟中间的组件没有任何关系,但是他们还必须把数据传递给下一级,就像公交车上,从后门递公交卡到前门刷一样,中间的人的心理OS其实是:
当然代码是没有情感的,不会觉得厌烦,但是由于中间每一层都需要传递数据给下层,一旦某些数据发生改变,就造成了中间层级的重新render,浪费了浏览器性能的同时,增大了调试的难度,而且接收数据的组件还要考虑“中间那些牲口们有没有动我的数据”?!
Round 3:
所以,为什么一定要让顶级的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在不同的层级上。
Round 4
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来。
如果这篇文章指导的方向有错误,里面有很多的问题,该怎么办?
欢迎指出和讨论,一切问题都会认真回答,虚心接受。
如果我也答不出来,那我会当作没看到...
关于React的Container&Presentational Component模型结构分析的更多相关文章
- React.createClass和extends Component的区别
React.createClass和extends Component的区别主要在于: 语法区别 propType 和 getDefaultProps 状态的区别 this区别 Mixins 语法区别 ...
- 5、手把手教React Native实战之盒子模型BoxApp
用HTML5和React Native分别实现盒子模型显示 写法不一样: 1.样式 ![样式不同](http://image17-c.poco.cn/mypoco/myphoto/20160323/0 ...
- React Native 中的component 的生命周期
React Native中的component跟Android中的activity,fragment等一样,存在生命周期,下面先给出component的生命周期图 getDefaultProps ob ...
- React 的 PureComponent Vs Component
一.它们几乎完全相同,但是PureComponent通过prop和state的浅比较来实现shouldComponentUpdate,某些情况下可以用PureComponent提升性能 1.所谓浅比较 ...
- React 设计模式 --- Container and Presentational pattern(容器和展示组件分离)
在React开发中,一个典型的React组件通常会混杂着逻辑操作部分和展示部分.逻辑操作部分指的是和页面UI无关的内容,如API的调用,数据的处理,事件处理函数. 展示部分则指的是创建页面UI 的内容 ...
- 展示组件(Presentational component)和容器组件(Container component)之间有何不同
展示组件关心组件看起来是什么.展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态.(子组件)容器组件则更关心组件 ...
- React Native - FlexBox弹性盒模型
FlexBox布局 1. 什么是FlexBox布局? 弹性盒模型(The Flexible Box Module),又叫FlexBox,意为"弹性布局",旨在通过弹性的方式来对 ...
- [React Native] Create a component using ScrollView
To show a list of unchanging data in React Native you can use the scroll view component. In this les ...
- [React] Write a stateful Component with the React useState Hook and TypeScript
Here we refactor a React TypeScript class component to a function component with a useState hook and ...
随机推荐
- 禁止复制(copy),禁用鼠标右键!
<SCRIPT> //加入页面保护 function rf() {return false; } document.oncontextmenu = rf function keydown( ...
- CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅
首页 登录注册 CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅 阅读 8113 收藏 927 2017-09-26 原文链接:github.com 腾讯云容器服务CSS,立 ...
- poj 2528 Mayor's posters 线段树 || 并查集 离线处理
题目链接 题意 用不同颜色的线段覆盖数轴,问最终数轴上有多少种颜色? 注:只有最上面的线段能够被看到:即,如果有一条线段被其他的线段给完全覆盖住,则这个颜色是看不到的. 法一:线段树 按题意按顺序模拟 ...
- MySql视图笔记(转载)
1. 视图的定义 视图就是从一个或多个表中,导出来的表,是一个虚拟存在的表.视图就像一个窗口(数据展示的窗口),通过这个窗口,可以看到系统专门提供的数据(也可以查看到数据表的全部数据),使 ...
- 模块(python的标准库)
在python中叫做模块,其他语言中叫做类库.python中的模块有三种:内置模块,第三方模块,自定义模块. 模块的使用: 先导入,import+模块名,再使用,模块名+函数名() .py文件与.py ...
- nodejs Centos环境搭建
使用二进制文件安装: node 环境下载 https://nodejs.org/en/download/ 下载里面的windows 安装包 和 linux 安装包 1)windows安装 window ...
- NYOJ 20.吝啬的国度-DFS+STL(vector保存上一节点)
整理代码 吝啬的国度 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第 ...
- MySQL备份工具收集
说明:MySQL的备份不像SQL Server那么的简单,备份时需要分数据库引擎类型,现在主流的就两个:InnoDB和MyISAM,而这两种类型备份方式各不一样. MyISAM: mysqlhotco ...
- mariadb设置utf8mb4
1 . mysql真正的utf8是utf8mb4才是有效的utf8 a). mariaDB的设置方法 #vim /etc/my.conf [mysqld] character_set_server=u ...
- php设置报错级别
ini_set("display_errors", "On");//若页面不报错的话,请设置php.ini 的display_errors 为 On error ...