从 React 谈 Web UI 开发

简介: 此前我在 Twitter 上这样表达过对 React 的理解,但是 Twitter 篇幅有限,所以在这篇文章里,我要做更详尽的阐述。

原文作者:UC 国际研发 Randy

微博:米斯特软的


image.png

此前我在 Twitter 上这样表达过对 React 的理解,但是 Twitter 篇幅有限,所以在这篇文章里,我要做更详尽的阐述。

我从前不喜欢 React, 是因为写 React 的 render function 不像写 template 一样方便,尤其是存在复杂的判断渲染的时候,Vue 的 template 一个 v-if 就搞定了。而在 React 里写,需要把这个判断写成 function, 然后条件判断 return 哪一个 view. 这是我最初对 React 的偏见所在之一。

然而经过自己的实践和思考,加上阅读一些文章,我发现以前的想法是错的。我在使用 React 的时候,没有做到 Thinking in React. 从而对 React 产生了不解和困惑。

有很多人把 React 当成框架来用,这是用不好 React 的根本原因。很少人认真思考 A JavaScript library for building User Interface 背后的含义,把 React 用得一团糟。

何谓 For Building User Interface? 意思就是,这个库仅仅是用于构建 UI 的,这是 React 本质要解决的问题。我甚至和很多人说,事实上 React 本身是不是 React 已经不重要了,重要的是我们写 UI 的思维。React 这个 library 本身仅仅是用来实现这个思维的手段。React 提供的,是优秀的 DOM diff 算法,和一套 Component system。换成代码来说,也就是:

image.png

这是 React building UI 的核心思想,所有的组件,就是接受 state, 返回一个 View. 这样看上去比较抽象,比如我们有一个 Clock 组件:

image.png

Clock 是一个 function, 接受一个 time 参数,返回的是一串 HTML String. 在程序里,我们可以给一个 Interval, 每秒传一个当前的 time, 得到一个新的 HTML String, 然后 apply 到某个 DOM 上。

image.png

这样的实现是能达到目的的,但是问题在于,每次 innerHTML 时,整个 #app 的 DOM 树会被重新渲染。

image.png

我们都知道,DOM 更新的花费是昂贵的。整个 DOM 树,实际上只是一个 span 在不断变化,所以我们需要 DOM diff 算法来得知到底哪一个 DOM 节点才需要被更新,从而节省开销:

image.png

在 React 里,把 props 传入,返回一个类似 HTML 的结构,然后 render 到指定的 DOM 节点上。这里 React 会算出哪个节点应该被更新:
image.png

我们这样手动去 setInterval 然后 render 未免有点傻,我们可以通过更改 state (也就是通常用到的 setState) 自动地让 React 随着 state 的改变而重新 render. 这里的 time 就是一个 state. 这叫做 Reactive.

Functional Programming 里有 Pure Function 的概念。Pure Function 之所以 Pure, 是因为不存在 side effect. 举个例子,我们写一个求和 function:

image.png

这个求和函数就是一个 pure function. 因为函数内部没有对 input 做任何改变,并且返回一个新的值。我传 1 和 1,得到的永远是 2.

Pure Function 的好处是利于维护和测试。要测试一个 Pure Function, 仅仅是传不同的值,预言对应的返回值。

现在回头看 React 的 Component, 也可以算是一个 Pure Function——接收不同的 props, 然后 render 对应的 View. 上面 Clock 的例子,props 和返回的 View 是映射关系。

光是 state => View 还不够,在构建 UI 的时候,我们希望 state 改变的时候,立即 rerender 整个 View, 也就是我们经常用到的 setState().

这样就很容易理解为什么我说 React 仅仅是实现构建 UI 思想的手段,因为构建 UI 的思想总结起来就是:

State 是 Reactive 的 (比如 React 的 setState)

state => View (依靠 DOM diff)

View 组成 Component

管理 state (依靠第三方的 state manager)

无论是 React 还是 Vue, 大抵都是这样的思想。Vue 1 还不完全是,Vue 2 就更接近了,只是后者写法既可以写得像 template, 又可以写直接写 vdom.

而开发者常常感到困难的地方实际上是上面的第 4 点——管理 state. 写 React 写得痛苦,大部分原因是用把 library 当成 framework 去用,把处理 state 的逻辑瞎写到 View 层中去,也就是所谓的 Dump Component.

改变 state 是 side effect, 我们应该把它从 View 层中分离出去。我多次提到,View 层真正要做的,仅仅是根据 state 返回对应的 View. state 的变化逻辑,应该在给 state manager 库去做,例如 Redux, Mobx. 下面我用 Mobx 作为例子:
640 (7).gif

https://jsbin.com/fumerup/edit?js,output

如果没有接触过 Mobx 不用慌张,只需要知道,Mobx 的 Observable 变化时,被 observer 包装的 React 组件会重新渲染。使用 state manager, 明显地分离了 View 和 side-effect:

image.png

测试这样的程序,首先为 side effect 的逻辑做测试,再为 View 做测试。View 的测试在这里就十分简单了,给他传一个 store 实例,借助 enzyme 之类的 testing utilities 预言不同的 action 得到的返回 View.

React 是 Reactive Programming 在 Web User Interface 上实现的手段,它只不过是一个库,提供了reactive render, component system 和降低开销的 DOM diff 算法. 把 React 换掉,只要不是手动操作 DOM, 其它的框架也不过大同小异。重要的是理解它背后的思想。说到底,前端开发在解决什么问题,用什么样的方式解决问题,在使用任何框架和库之前先把这两个问题思考明白,就不会认为前端难学了。

目录
相关文章
|
29天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
160 45
|
12天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
11天前
|
前端开发 安全 JavaScript
2025年,Web3开发学习路线全指南
本文提供了一条针对Dapp应用开发的学习路线,涵盖了Web3领域的重要技术栈,如区块链基础、以太坊技术、Solidity编程、智能合约开发及安全、web3.js和ethers.js库的使用、Truffle框架等。文章首先分析了国内区块链企业的技术需求,随后详细介绍了每个技术点的学习资源和方法,旨在帮助初学者系统地掌握Dapp开发所需的知识和技能。
2025年,Web3开发学习路线全指南
|
18天前
|
存储 前端开发 JavaScript
如何在项目中高效地进行 Web 组件化开发
高效地进行 Web 组件化开发需要从多个方面入手,通过明确目标、合理规划、规范开发、加强测试等一系列措施,实现组件的高效管理和利用,从而提高项目的整体开发效率和质量,为用户提供更好的体验。
27 7
|
22天前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
22天前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
35 2
|
1月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
49 1
|
1月前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
1月前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
55 2