换一个角度来审视React

简介: a. React是什么• 前端场景下MVC架构• Flux设计模式• Redux + React = MVCb. JSX• 手动实现一个JSX转换器


如果你觉得可以,请多点赞,鼓励我写出更精彩的文章🙏。
如果你感觉有问题,也欢迎在评论区评论,三人行,必有我师焉


概要

  1. React是什么
  1. JSX

这是一次公司组内分享的内容,本来是想写一篇关于 React_Fiber源码相关的东西,但是在分享的过程中发现大家对 React一些常规 API如何使用倒背如流。但是如果在继续深究或者说上升到架构层面的问题,就有点含糊不清了。(这种情况在我和其他技术人员讨论的时候,也存在诸如此类的问题,其实这不是大家的错,而是 React这个 所牵扯的东西太过于庞杂。不是不想学,而是学不动了。谁不想在996之后,峡谷溜达会。)所以,我抱着,我不下"地狱",谁下地狱的决心,来用我 浅薄的知识点,用另外一种角度来简单的描述一下 React是什么。这其中有我自己对一个东西的认知和见解,如果和大家所掌握的知识所不同,欢迎大家在评论中指出和一起讨论。毕竟, There are a thousand Hamlets in a thousand people's eyes

时间不早了,该干点正事了,咱们书归正转。 (郭德纲语音包) 👈 点击触发

React是什么

我们在接触一个人或者一件事,可能会经历是什么👉为什么👉怎么办,也就是What => Why =>How三部曲。

所以,我们该篇文章也按着这个流程来。

我们来一个直击灵魂的问题,React 是什么

在和一些刚接触框架的新前端er交流的时候,猛然发现一个支持度很高的说辞。

React 是MVC框架的实现

其实如果按照从架构的角度来考虑,这个答案是政治正确的。也就是说,说你错误吧,挑不出啥毛病,但是承认你正确吧,总有一种如鲠在喉的感觉。

但是,其实说一个东西是XX,需要一个context

其实,关于React是什么的这个问题,React官网早已给出了答案。

A JavaScript library for building user interfaces

"地主老爷",把话说的很明白了 => React 就是一个UI库,他带着他家三个打手Declarative/Component-Based/Learn Once, Write Anywhere。一起用棍棒在敲打来福

其实,这也是React 对于新手来说,比较难入门的地方,因为想要实现一个页面,用了人们口中所谓的 框架。但是这个框架却只负责页面的展示,那势必就需要利用辅助性工具来将应用能够跑起来。而这些辅助性工具。不乏针对路由控制的 react-router,还有针对页面状态控制的redux

而一个真正的应用,势必是需要状态控制的。这不,我们即将介绍的主角👉redux正在缓缓向我们走来。


前端场景下MVC架构

该篇幅所说的,仅代表个人观点!如有雷同,不胜感激!如有不同的看法,也欢迎评论区指出。

在介绍即将出场的主角之前,我们还需要有一个前置知识点。什么是MVC

想必大家无论是在面试还是在学习的工作中,总是会看到这个概念。 xxx框架是MVC框架的实现。就像我们上文描述的一样。有些人说React 是MVC框架的实现。那到底什么是MVC呢。

其实MVC这种架构模式,是为了实现代码分离或者用一个更拽的词-关注点分离

MVC是三个单词的首字母缩写,它们是Model(模型)、View(视图)和Controller(控制)。

模型(Model):程序需要操作的数据或信息 视图(View):用户界面 控制器(Controller):用于连接 View 和 Model,管理 Model 与 View 之间的逻辑

服务端MVC架构模式中,有一个很突出的特点,就是单向数据流

但是但是但是,此处有转折,上面介绍的MVC的概念中有一个很重要的点,就是单向数据流。但是在前端场景下,MVC其实被无形中变更为双向数据流了。

这里放一张,我比较认同的关于前后端MVC层级划分的汇总。

然后继续看前端MVC中数据是如何流向的。

案例: 用户点击页面某个button( view),而button绑定了对应的事件回调( Controller),而该事件回调所要做的就是改变button的innerText( Modal)

除了允许用户通过 View 层交互来触发流程以外,MVC 架构还有另外一种形式,即允许用户通过直接触发 Controller 逻辑来触发流程

案例: 用户通过DOM提供的API, 绕过页面,直接获取了页面中某个button的实例,而button绑定了对应的事件回调( Controller),而该事件回调所要做的就是改变button的innerText( Modal)

前端应用/框架往往出于交互的需要,允许 View 和 Model 直接通信

其实,大家可能此时对前端MVC 概念感到懵逼,如果给大家看几个图片,就会有点感觉了。

在前后端还未分离之前,负责拼装页面的任务其实在服务端。例如 JSP(Java Server Page)

在有了Node以后,前端可以拥有属于自己的资源服务,并且拥有自己的路由系统。这样,就把原本需要后断提供的UI层,移到了前端范围。

其实是什么是Js的MVC?Js的MVC只是后端MVC中的View里面再去分出来的MVC,跟后端MVC没太大关系。前端的MVC是为了解决复杂前端情况下模块化 Js 的问题。最典型的应用,单页面的 Js 应用。

针对MVC架构绕的有点远了。好了,咱们--收。

为什么要讲MVC框架,其实为了引出Flux的设计模式。


Flux

Flux is the application architecture that Facebook uses for building client-side web applications. It complements React's composable view components by utilizing a unidirectional data flow. It's more of a pattern rather than a formal framework.

这段描述是从 Flux官网中找到的。

我们从其描述中可以得到以下的观点

  • 1:用于客户端(client-side)应用的架构。
  • 2:提供单向数据流
  • 3:它更偏向于设计模式

我们通过如上的图,可以看到在Flux流程中有四个节点。

Action Dispatcher Store View
对变化的描述 用来接收Actions、执行回调函数 用来存放应用的状态,
一旦发生变动,就提醒Views要更新页面
视图层

我们用一个简单的🌰来看看Flux是如何运行的。 由于Flux现在已经被Redux替换,所以我就直接CV官网的例子,来简单展示一下数据流向。


Redux + React = MVC

其实我们在上面讲了很多和React关系不大的废话,只是为了用更多的角度来反面论证

React 是MVC框架的实现,如果单纯从React本身来讲,是站不稳的。(是站不稳,不是站不住,我为了免于同行打脸,给自己留了些许的余地)。

那如何描述才会能变的不那么让人感觉这个论调是成立的。换句话说,在何种场景下,才可以说React是前端MVC的一种实现呢。

注意措辞。React在Redux的加持下,才算的上是一个比较经得起考验的前端应用。

React+ Redux = MVC

无论从MVC的概念还是从React库本身的职责考虑,React真的算不上真正意义的MVC框架。

我们来简单的描述一下Redux的工作流

ReduxA Predictable State Container for JS Apps

其实,Redux的出现,是为React提供了一套完整的数据管理。充当着MVC架构中的M M和C 的作用。

Redux是Flux架构模式的具体实现,所以有些概念也是和Flux一脉相承。

Redux 主要由 3 部分组成:Store、Reducer 和 Action。

  • Store:一个单一的数据源,而且是只读只读的。
  • Action 对变化的描述。
  • Reducer 是一个函数,它负责对变化进行分发和处理,最终将新的数据返回给 Store。

这里可能有一个疑问,View是如何知道Store数据变化的。

我们通过Redux的源码来分析下。

首先,在view通过调用store中subscribe(()=>{})注册对应的回调函数。会将对应的事件回调push到一个全局Listeners数组中。

其次,在dispatch(action)的时候,在reducer计算出最新的state之后,就会依次调用存在全局的回调函数。

由于篇幅有限,下面的代码做了些删减。


还有一点还需要说明的,很多人总感觉Redux是针对React所构建的。其实不是,他是一个用于管理前端应用数据流向的库。正如官网说的,Redux可以使用于任何前期框架。

而如果熟悉React的同学,并且用Redux作为前端数据管理。肯定接触过react-redux。 而利用了react-redux之后,就不必要每次在需要监听store变化的组件中调用subscribe。而是用了一种更优雅的方式来做。

将组件通过HOCconnect包裹,并重新返回一个增强版的组件。

其他具体的API就不在这里赘述了。如果想了解更多关于Redux的源码,可以看我原来写的纯手硬撸Redux

现在我们只简单介绍connect是如何实现的。

其实还是换汤不换药,在Redux中如果想监听它数据变更,就需要通过store.subscribe()来注册回调函数。

总结:其实在上面费了好多的时间去解释什么是React,什么是前端MVC。

其实用一句话就能概况React就是一个UI库

而我还决定,用很大篇幅去,婆婆妈妈的去讲解这些概念。👉最终的目的,就是想从框架的角度出发,让大家用一个全新的角度去了解React的数据流。而React本身的数据流(单向数据流),被别人估计都讲烂了。所以,我就没有拾人牙慧。


JSX

在进行React开发时,大家习惯上用JSX来表示页面结构,而在通过ReactDOM.render处理以后,所写的页面结构就跃然纸上。

那什么是JSX呢?

按照 React 官方的解释,JSX 是一个 JavaScript 的语法扩展,或者说是一个类似于 XML 的 ECMAScript 语法扩展。

关于JSX的其他相关知识点,可以参考官网JSXJSX In Depth

而我们今天换一种角度来考虑JSX。 既然JSX是JS的语法扩展,就需要有一个很直接的认知。常规浏览器是无法识别的。 既然,无法识别,就需要通过一些方式将其转换为浏览器能够识别的语法。 类似于ES6+的语法,需要通过处理才可以被浏览器识别。

而这个处理,就是通过babel通过指定对应转换规则,将其转换为常规的浏览器能够识别的语法。

而babel其实内核就是一个JS编译器

接下来,我们通过实现一个自定义的babel-plugin来了解这个过程。

在介绍代码之前,我们需要对编译器流程有一个大致的了解。

大多数编译程序(compiler)分为三个步骤:Parsing(分析阶段)/Transformation(转换)/Code Generation(代码生成或者说生成目标代码)

Parsing Transformation Code Generation
将源代码(raw code)转换为AST(抽象语法树) 接收Parsing生成的AST,并且按照compiler内定的规则进行代码的转换 接受被compiler转换过的代码,按照一定的规则将代码转换为最终想要输出的代码格式。

由于篇幅有限,我们就直接CV代码了。如果想真正了解compiler的处理过程,可以参考我原来写的文章。编译程序(compiler)的简单分析代码来构建一个简单的compiler

手动实现一个JSX转换器

我们通过babel来对一个JSX的文件进行转换。

.babelrc ==>babel配置文件

jsx-parser.js jsx-plugin.js

test.jsx

function JSX(){
  return <div><span>Hello JSX</span></div>
}
复制代码

我们通过 babel test.jsx来开启babel转码。处理结果如下:

有几点需要注意下:

  • 1 启动本地babel转码需要在本地或者全局按照 babel-cli 👉 npm install babel-cli -g
  • 2 在配置文件中,执行方向是从右往左进行的。
  • 3 在将JSX转换为React.createElement配合React将其转换为对象,而这个对象就是我们平时所说的Virtual DOM

这篇文章是为了讲述一下React的框架层面数据流向。具体例如setState是同步异步,Fiber架构如何实现。由于需要很大的篇幅去描述。所以,打算重新开一篇来描述。

相关文章
|
8天前
|
前端开发 JavaScript 算法
React 运行时的难点和挑战
【10月更文挑战第25天】深入研究React运行时需要开发者具备扎实的JavaScript基础、对React框架的深入理解以及丰富的实践经验。只有克服这些难点和挑战,才能更好地发挥React的优势,构建出高性能、高质量的用户界面和应用程序。
|
9天前
|
前端开发 JavaScript 开发者
“揭秘React Hooks的神秘面纱:如何掌握这些改变游戏规则的超能力以打造无敌前端应用”
【10月更文挑战第25天】React Hooks 自 2018 年推出以来,已成为 React 功能组件的重要组成部分。本文全面解析了 React Hooks 的核心概念,包括 `useState` 和 `useEffect` 的使用方法,并提供了最佳实践,如避免过度使用 Hooks、保持 Hooks 调用顺序一致、使用 `useReducer` 管理复杂状态逻辑、自定义 Hooks 封装复用逻辑等,帮助开发者更高效地使用 Hooks,构建健壮且易于维护的 React 应用。
22 2
|
2月前
|
JavaScript 前端开发 算法
react只停留在表层?五大知识点带你梳理进阶知识
该文章深入探讨了React进阶主题,包括PropTypes与默认属性的使用、虚拟DOM的工作机制、Refs的高级用法、生命周期方法的详解以及CSS动画在React中的集成技巧。
|
3月前
|
前端开发 测试技术 UED
React性能优化的神奇之处:如何用懒加载与代码分割让你的项目一鸣惊人?
【8月更文挑战第31天】在现代Web开发中,性能优化至关重要。本文探讨了React中的懒加载与代码分割技术,通过示例展示了如何在实际项目中应用这些技术。懒加载能够延迟加载组件,提高页面加载速度;代码分割则将应用程序代码分割成多个块,按需加载。两者结合使用,可以显著提升用户体验。遵循合理使用懒加载、编写测试及关注性能等最佳实践,能够更高效地进行性能优化,提升应用程序的整体表现。随着React生态的发展,懒加载与代码分割技术将在未来Web开发中发挥更大作用。
45 0
|
设计模式 缓存 前端开发
|
设计模式 JSON 前端开发
|
编解码 前端开发 JavaScript
这次终于搞清楚移动端开发了(一)
这次终于搞清楚移动端开发了(一)
|
编解码 前端开发 UED
这次终于搞清楚移动端开发了(二)
这次终于搞清楚移动端开发了(二)
|
Web App开发 JavaScript 前端开发
这次终于搞清楚移动端开发了(三)
这次终于搞清楚移动端开发了(三)