查看前端页面请求的文件地址_困扰99%前端新手的"状态管理"究竟是啥意思?...

前言

之前有小伙伴问我,经常在各种前端框架的文档中看到的“前端状态管理”究竟是什么意思,他始终弄不懂。我想可能初学前端的同学多少都会对这个概念比较懵,状态管理又是现代的前端框架中非常核心的内容,不理解这个就很难完整的理解React/Vue这类框架, 那我就写一篇文章来解释一下这个概念吧。

前端状态

首先说说什么叫“前端状态"。所有程序都有“状态”,状态表现在代码中其实就是各种类型的变量,其实程序运行的过程就可以理解为是程序内部的“状态“发生改变的过程,而我们编写的程序就是在控制这些“状态”如何发生改变。

前端状态的概念主要是应用在单页应用SPA(Single Page Application)中的,是在React/Vue等现代化的前端框架流行起来之后才有的一个提法,之前的jQuery时代是没有这种概念的。

SPA

那么SPA和之前的网页有什么区别呢?其实最本质的区别就是"服务端渲染“和”前端渲染“的区别。

所谓服务端渲染,是指浏览器请求一个URL地址,服务端返回的HTML页面是完整的,浏览器直接展示这个HTML内容再加上CSS的样式即可。JS主要做一些辅助性的特效或其他工作。

而前端渲染,是指浏览器请求一个URL地址,服务端返回的HTML页面并不包含具体内容,而是会通过 script标签引入一个JavaScript文件。浏览器只有通过解析和执行JS代码页面上才会展示出内容,否则页面就是空白的。而且后续的页面更新也都是在JS中完成,而不是通过跳转到另一个URL地址来完成(这也是单页应用名字的由来)。当然这里并不是指URL地址就一定不会变化,而是说页面不会“刷新”。

SPA的出现使得Web前端成为真正的"客户端程序",可以独立完成渲染(DOM API)、网络请求(XHR,fetch)等任务,也就是所谓的"前端渲染",而不是只是一个“网页展示器”。

声明式编程和命令式编程

前端状态管理之所以流行的另一个原因是,现代的前端框架包括React/Vue都是声明式的编程方式,而之前的jQuery是命令式的。所谓声明式,就是说你在代码中不会直接去操作UI,而是通过操作数据,来间接地改变UI内容。而命令式,是直接操作UI的,这就导致数据层和展现层通常是不作区分的。

声明式的编码方式天然的会把数据状态和页面代码分离,所以更需要一套独立的状态管理系统。

Todo App示例

上面是从概念上解释,接下来我们举一个实例来解释一下这个概念。这里举一个很简单的Todo App:

a3cdd30736e2d2b7f06d5c4303eab9d2.png

65b2587327ee0a1980fa67b480cddf99.png

上面两张图分别是列表页和详情编辑页。列表页中的内容是在打开首页的时候从服务端通过请求来的。点击列表页中的一个标题,会进入到详情编辑页,要求在编辑页中显示的标题要和列表页的标题对应。在编辑页可以编辑标题和内容,点击Save按钮会返回到列表页,这里页要求列表页的标题内容更新为新的标题。

产品需求介绍完了,我们先来看一下如果是服务端渲染的方式,是如何工作的。

首先,当你在浏览器中输入https://todo.com/网址的时候,浏览器向你的服务端发起HTTP请求,你的服务端返回给浏览器HTML文件。这个HTML文件中包含了完整的Todo List的内容。浏览器只需要解析HTML代码以及CSS然后展示即可。

列表中的每一项都是一个<a href="/:id">标签,比如当你点击id为1的一个标题的时候,浏览器会“跳转”到https://todo.com/1的地址。这时候会向你的服务器发送另一个HTTP请求,URL就是https://todo.com/1。你的服务器又会针对这个地址返回对应的HTML文件,同样的,这个HTML文件也是有完整内容的,浏览器要做的仅仅是展示HTML内容。

这里的"Save"按钮会是一个form Submit按钮,它会使浏览器向你的服务端发送一个POST请求,并带上你在页面中新输入的标题和内容。你的服务器收到请求之后,会把新输入的内容保存数据库,然后返回一个"Redirect",使你的浏览器重新跳转到列表页。

然后我们看一下如果是前端渲染的方式:
你在浏览器中输入了网址:https://todo.com/,浏览器向你的服务端发起HTTP请求,然后你的服务器返回HTML文件。这一步是没有区别的,区别就在于服务端返回的那个HTML文件的内容。在服务端渲染的情况下,这个文件是由服务端“拼装”出来的,而在前端渲染的情况下,这个文件不包含任何内容,而只是引入了一个JS文件。比如下面这样的:

<html>
 <head>
  <script src="/app.js"></script>
 <head>
 <body>
 </body>
</html>

当这个文件到达浏览器,因为HTML的body部分是空的,所以在执行JS之前页面会是空白的。接下来浏览器会下载和执行JS代码。

在JS代码中,你会使用XHR的方式向服务器发起一个“API请求“,这类请求是浏览器在后台发起,不会引起地址栏和页面刷新。和页面请求不同,服务器对这种“API请求”的响应内容通常会是JSON格式的(服务器通常是根据不同的请求路径判断是页面请求还是API请求,比如/api/*开头的请求都算作API请求)。比如,请求列表的URL是:GET /api/todos,它的响应是:

[
 {
 "id": 1,
 "title": "title1",
 "content": "This is list 1 content",
 }
 ,...
]

收到响应之后,JS代码会被执行,之后会由JS执行DOM操作来改变页面的展示内容,也就是页面内容被“渲染”出来了。

这个列表页面中的每一条会是一个简单的<div>标签,而不是一个会发生浏览器跳转的<a>标签。当你点击其中一个标题的时候,同样会由JS代码接管。由于在请求列表的时候前端已经拥有了所有数据,所以这次不用再请求服务器了,JS代码直接重新操作DOM,来"渲染"出编辑页面即可。

当在编辑页面中点击Save按钮,同样触发JS代码,JS代码会向服务器发起一个保存修改的请求。如果服务器响应成功,那么JS会更新自身的数据,修改为新的标题和内容。

在这个例子中,所谓的前端“状态”,可能就是一个全局的JS对象,比如:

{
 "todos": [
 {
 "id": 1,
 "title": "title1",
 "content": "This is list 1 content",
 }
    ,...
 ]
}

而所谓的"状态管理",其实就是对这个全局对象的一系列增删改查的操作。

通过上面的例子,我们可以看一下前端状态管理的意义有哪些:

第一,数据管理逻辑和页面渲染逻辑分离,使得代码更容易维护。这其实有点类似于MVC的设计模式,操作数据的地方不会关心页面如何展示,展示页面的地方不会关心数据从哪里来的。

第二,可以保证数据有一份“唯一可信数据源“。比如上面例子中的“title"字段,在列表页面和编辑页面都会展示,如果不对这个状态做统一管理,很难保证数据的统一:比如在修改页面修改了之后要保证列表页面同步修改。在实际的项目中,同一份数据可能在N多个地方展示、修改,如果不做好状态管理,代码会写成什么样简直不敢想。

总结

看到这里,我不知道你会不会觉得奇怪,“不是要讲前端状态管理吗,为什么长篇大论的讨论服务端渲染和前端渲染?“。其实我是觉得因为有了单页应用的需求(为了解决浏览器刷新的用户体验问题),所以需要前端渲染;而因为有了前端渲染,所以前端不得不需要自己管理状态。理解了前端渲染的整个流程,对于理解前端状态管理是个前提,也有很大帮助。

不知道你现在对前端状态管理的概念有没有清晰一些。这篇文章主要介绍概念,并没有涉及具体框架的描述。其实理解了概念再去看redux/vuex这些框架,会容易理解很多。

如果你对前端技术感兴趣请关注我的公众号<前端时光机>,所有文章都会在那里首发,谢谢。

3f453fde620d7aa743e332db871f308d.png
分析一下这个json {&quot;name&quot;:&quot;12312&quot;,&quot;project_id&quot;:&quot;87156&quot;,&quot;project_name&quot;:&quot;上上下下左左右右baba与聚法科技(长春)有限公司与公司、证券、保险、票据等有关的民事纠纷&quot;,&quot;client&quot;:&quot;[{&quot;type&quot;:&quot;自然人&quot;,&quot;customer_id&quot;:&quot;80236&quot;,&quot;customer_name&quot;:&quot;上上下下左左右右baba&quot;}]&quot;,&quot;sign_date&quot;:&quot;2023-06-06&quot;,&quot;expire_date&quot;:&quot;2023-06-21&quot;,&quot;subject_amount&quot;:&quot;123&quot;,&quot;contract_amount&quot;:&quot;123&quot;,&quot;charge_method&quot;:&quot;一次性,分阶段,风险,计时&quot;,&quot;equity_amount&quot;:&quot;13811&quot;,&quot;amount_info&quot;:&quot;[{&quot;type&quot;:&quot;一次性&quot;,&quot;pay_date&quot;:&quot;2023-07-03&quot;,&quot;charge_amount&quot;:&quot;12&quot;},{&quot;type&quot;:&quot;分阶段&quot;,&quot;pay_date&quot;:&quot;2023-06-13&quot;,&quot;charge_amount&quot;:&quot;123&quot;,&quot;is_satisfy&quot;:&quot;是&quot;,&quot;pay_condition&quot;:&quot;12312&quot;},{&quot;type&quot;:&quot;风险&quot;,&quot;pay_date&quot;:&quot;&quot;,&quot;charge_amount&quot;:&quot;&quot;,&quot;is_satisfy&quot;:&quot;是&quot;,&quot;pay_condition&quot;:&quot;123&quot;,&quot;basic_amount&quot;:&quot;123&quot;,&quot;risk_amount&quot;:&quot;12&quot;,&quot;object_amount&quot;:&quot;123123&quot;,&quot;object&quot;:&quot;赔偿金&quot;,&quot;risk_prop&quot;:&quot;13213&quot;,&quot;member&quot;:&quot;&quot;,&quot;rate&quot;:&quot;&quot;,&quot;hours&quot;:&quot;&quot;},{&quot;type&quot;:&quot;计时&quot;,&quot;member_id&quot;:&quot;392159&quot;,&quot;member&quot;:&quot;曹野&quot;,&quot;rate&quot;:&quot;11&quot;,&quot;hours&quot;:&quot;1231&quot;}]&quot;,&quot;seal_person&quot;:&quot;123&quot;,&quot;seal_type&quot;:&quot;律所公章,法人名章,财务章&quot;,&quot;seal_num&quot;:&quot;123&quot;,&quot;file_path&quot;:&quot;[{&quot;title&quot;:&quot;导入错误数据 (15).xls&quot;,&quot;path&quot;:&quot;382585/1686381522542/导入错误数据 (15).xls&quot;,&quot;size&quot;:&quot;91136&quot;},{&quot;title&quot;:&quot;3.txt&quot;,&quot;path&quot;:&quot;382585/1686561731102/3.txt&quot;,&quot;size&quot;:44078}]&quot;,&quot;remark&quot;:&quot;123123&quot;} 并使用php转换成字符串
最新发布
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值