如今,无论是国内还是国外,React 成为主流框架的势头似乎无可阻挡。作为一名曾在 Vue 的世界里摸爬滚打的老兵,我再次投身于 React 的战场,感受到一股新的活力和挑战。
本文将直击核心——探讨“数据驱动视图”的理念,带您了解 React 如何超越传统的 JavaScript DOM 操作思维。我们将比较 Vue和 React 框架的不同体系结构——前者基于 MVC (模型-视图-控制器),而后者则采用了 MVVM(模型-视图-视图模型)架构。最后,我们将简单介绍 React 中 JSX 的基本细节,帮助您快速入门这一强大的前端工具。
01 | React 数据驱动视图思想
在 React 的世界里,一切皆由数据主宰。我们通过操作数据来触发视图的变化,当数据发生变动时,React 会根据最新的数据状态自动重新渲染页面。虽然 React 的底层实现仍然依赖于 DOM 来完成最终的视图呈现,但它巧妙地引入了虚拟 DOM 的概念,使得视图更新更加高效。(后文教你“忘记dom”)
1)虚拟 DOM 到真实 DOM 的渲染体系
React 构建了一套从虚拟 DOM 到真实 DOM 的转换机制,这一体系不仅让开发者可以专注于数据逻辑而不必担心频繁的 DOM 操作所带来的性能问题,还有效地 避免了由于直接操作 DOM 引起的重排和重绘,从而显著提升了应用的响应速度和用户体验。
2)性能优化与开发效率
得益于虚拟 DOM 的存在,React 应用在处理复杂界面更新时表现得尤为出色。它不仅提高了代码的可维护性和复用性,还为开发者带来了更高的开发效率。React 让我们可以更专注于构建用户交互和业务逻辑,而不必过多操心浏览器端的性能瓶颈。
3)设计理念
在这个过程中,React 并未完全摒弃对 DOM 的操作,而是选择了一种更为智能的方式:仅需在应用启动时绑定一次根元素(root),之后所有的视图变化都交由虚拟 DOM 处理,直到需要同步到实际的 DOM 为止。这样的设计既保证了高效的视图更新,又不失灵活性,真正实现了数据驱动视图的思想。
// main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
//
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
)
React里面绑定一次dom ReactDOM.createRoot(document.getElementById('root'))
;
这就不得不说一下React16和现在使用的React18 创建和使用 根root
的区别了
- React 16
在 React 16 中,创建和更新应用的根通常使用 ReactDOM.render
方法。这个方法接受两个参数:一个是要渲染的 React 元素,另一个是 DOM 容器节点。例如:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
const container = document.getElementById('root');
ReactDOM.render(<App />, container);
想要更新应用程序的状态并重新渲染时,需要再次调用 ReactDOM.render
,传入新的 React 元素和相同的容器节点。这会导致整个组件树的替换,尽管 React 的内部优化可以避免不必要的 DOM 操作。
- 但是But React 18
React 18 引入了新的 Root API,提供了 createRoot
方法来替代旧的 ReactDOM.render
。新的 API 更加明确地将创建根和渲染操作分开,并且为并发特性和其他新功能铺平了道路。使用 createRoot
创建根之后,可以通过调用根对象上的 render
方法来初始化或更新应用:
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
const root = createRoot(container); // 创建根
root.render(<App />); // 初始渲染
如果需要在服务端渲染的应用上进行客户端水合(hydration),则应使用 hydrateRoot
而不是 createRoot
:
import { hydrateRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
const root = hydrateRoot(container, <App />); // 水合并渲染
总的来说,React 18 的新 Root API 是为了提供更好的性能、灵活性和开发者体验
02| MVC 与 MVVM 体系
React 框架采用的是 MVC 体系,而 Vue 框架采用的是 MVVM 体系。
-
MVC:
Model(模型) :数据层。
View(视图) :视图层。
Controller(控制器) :控制层。
- 需要按照专业的语法去构建视图(页面):React 中是基于 JSX 语法来构建视图的。
- 构建数据层:但凡在视图中,需要“动态”处理的(需要变化的,不论是样式还是内容),我们都要有对应的数据模型。
- 控制层:当我们在视图中(或者根据业务需求)进行某些操作的时候,都是去手动修改相关的数据,然后 React 框架会按照最新的数据,重新渲染视图,以此让用户看到最新的效果!
这里附上‘Max极客菌’对React的MVC图解
-
MVVM:
Model(模型) :数据层。
View(视图) :视图层。
ViewModel(视图模型) :视图监听层。
- 数据驱动视图的渲染:监听数据的更新,让视图重新渲染。
- 视图驱动数据的更改:监听页面中表单元素内容改变,自动去修改相关的数据。
这里附上‘Max极客菌’对Vue的MVVM图解
03| 忘记 DOM 操作
在 React 中,我们不需要直接操作 DOM,而是通过 JSX 来定义组件和数据绑定。
这里后续还会出一期JSX文章,这里先简单讲解jsx的细节
-
JSX:JavaScript 和 XML 的混合语法,类似于 HTML。常见使用有:
- 变量/函数:
{text}
- 数学运算:
{1+1} -> {2}
{x+y}
- 判断:三元运算符
{i===1?'OK':'NO'}
- 循环:借助于数组的迭代方法处理
{map}
- 变量/函数:
-
JSX 构建视图的基础知识
- 创建
.jsx
文件,支持 JSX 语法。 - 在 HTML 中嵌入 JSX 表达式,需要基于
{}
胡子语法。(花括号) - 在
ReactDOM.createRoot()
的时候,不能直接把 HTML/BODY 做为根容器,需要指定一个额外的盒子(例如:#root
)。 - 出现多个根节点则报错:相邻 JSX 元素必须被包裹在一个闭合标签内。
- React 提供了一个特殊的节点(标签):
React.Fragment
空文档标记标签<></>
。
- 创建
04| React 代码示例
建立App.jsx文件,在前文提到的main.jsx 根文件导入这个文件。
值得提一嘴的是,后缀.jsx
不同于.js
// APP.jsx 文件
import React from 'react'
import React from 'react'
// 全局
let styObj = {
fontSize: '20px',
color: 'red'
}
function App() {
const [count, setCount] = useState(0)
return(
// React.Fragment 空标签替代‘div’,不增加一个层级
<>
{/* 渲染按钮 */}
<button type="button" onClick={() => {
setCount(count + 1)
}}>按钮{count}</button>
<br />
<h2 style={styObj}>12.22早安,舒服!!</h2>
{/*jsx统治区注释 直接使用虚拟dom对象 */}
{React.createElement('button',null,'按钮')}
</>
)
}
export default App
当然渲染按钮进行状态更新时,可以使用函数进行封装某种操作,也算是代码进行复用吧
import { useState } from 'react'
import React from 'react'
function App() {
// useState 钩子函数,两个状态变量,count 是状态值,setCount 是更新状态值的函数
const [count, setCount] = useState(0)
const increment = () => {
// 三种都行,推荐第一种,第三种return还要{},适合多条语句
// setCount(count + 1)
// setCount(preCount => preCount + 1)
setCount(preCount => {return
preCount + 1
});
}
return(
<>
<button type="button" onClick={increment}>按钮{count}</button>
</>
)
}
export default App
我相信看到这里的小伙伴中肯定会出现绝世高手~
希望这篇文章对大家有帮助,欢迎评论区探讨学习,学会的话也还请给本文一个点赞支持哦~