react介绍
react是一个用于构建用户界面的JavaScript库,它原本是facebook的内部项目,用来构建instagram的,之后进行了开源,react主要关注的就是我们经常说的MVC模式中的V,拥有较高的性能
react特点
-
声明式设计
react是一种面向数据编程的框架,不需要去控制DOM在操作数据渲染,react会自己去帮你操作DOM,可以帮助开发者节省很多操作DOM的代码
-
JSX语法
JSX是JavaScript的语法扩展,react开发的大部分都使用JSX语法,简单来说,就是我们会在js代码里面看到html的标签语法
-
灵活
react所控制的DOM就只有一个id为root的DOM,页面上其他的DOM你可以通过使用比如JQ等框架,也就是说可以与其他库并存不存在冲突
-
单向数据流
react的数据流是单向的,父给子组件传数据,子组件可以直接调用,但是不能直接通过子组件修改传递过来的数据,比如this.props
-
虚拟DOM
这个其实是和vue一样的一个东西,使用虚拟DOM开发的好处就是当数据或状态发生变化的时候,会自动同步到虚拟DOM中去,并且仅将变化的部分同步到虚拟DOM中,也就是说并不会刷新整那个DOM树
创建react项目
在学习过vue之后,我们知道类似像这种组件化开发的框架我们一般都使用脚手架工具来搭建配置项目,react也有自己的脚手架工具
官方建议我们在学习react的时候可以使用官方自己的脚手架工具
create-react-app
create-react-app
是facebook官方推出的一个构建react单页面应用的脚手架工具,它内部集成了webpack来配置运行环境,并且还内置了一系列的loader来帮助我们可以实现零配置开发react项目
npx create-react-app 项目名称
注意:
在创建过程中有可能会出现以下警告
tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap
这里其实可以不同管它,主要是提示tar版本低了,让你升级,如果想让这个警告消失可以是执行
npm install -g tar@latest
升级到最新版即可。
这里我们执行的并不是npm而是npx,这里我们可以理解成我们并没有把这些脚手架工具下载到本地保存再通过脚手架工具搭建环境,npx 将create-react-app下载到一个临时目录,使用以后再删除。所以,以后再次执行上面的命令,会重新下载create-react-app。
创建好之后项目的目录结构基本上和之前通过vite创建vue项目的差不多,主要编辑的内容都再src文件夹内,这里面我们主要就看两个文件
index.js入口文件
import React from 'react'; //导入React
import ReactDOM from 'react-dom/client'; //导入用于创建虚拟节点的对象
import './index.css'; //导入全局样式
import App from './App'; //导入项目顶层组件app
import reportWebVitals from './reportWebVitals'; //导入性能指标
//将public文件夹中的index.html中id为root的元素作为挂载区域
const root = ReactDOM.createRoot(document.getElementById('root'));
//render方法用于在root挂载区域内渲染组件
root.render(
//采用React的严格模式渲染组件
<React.StrictMode>
<!-- 把顶层组件app进行渲染 -->
<App />
</React.StrictMode>
);
reportWebVitals(); //调用性能指标,我们可以通过reportWebVitals(console.warn);查看当前项目性能
扩展:
使用5.0版本的
create-react-app
脚手架创建的项目,新增了reportWebVitals.js
文件,这个webVital是Google提出的、检测用户体验的标准,这些指标包含三个关键指标(CLS、FID、LCP)和两个辅助指标(FCP、TTFB)。具体含义如下:
LCP (Largest Contentful Paint):最大内容渲染时间。指的是从用户请求网址到窗口中渲染最大可见内容所需要的事件(最大可见内容通常是图片或者视频,或者大块的文本)。FID (First Input Delay):首次输入延迟。指的是从用户首次与网页互动(点击链接、按钮等)到浏览器响应此次互动直接的时间。用于判断网页进入互动状态的时间。
CLS (Cumulative Layout Shift) :累计布局偏移,得分范围0-1,指的是网页布局在加载期间的偏移量,0表示没有偏移,1表示最大偏移,这个指标指示用户与网站的交互体验,如果网址在加载过程布局一直跳动,用户体验会很差。比如加载一张图片,但没有大小空白占位,导致图片显示时页面高度跳动。
FCP(First Contentful Paint)首次内容绘制。标记浏览器渲染来自 DOM 第一位内容的时间点,内容可能是文本、图像等元素。
TTFB (Time to First Byte) 首字节到达的时间点。
App.js顶层组件
import logo from './logo.svg'; //导入logo图片
import './App.css'; //导入组件样式
//这个App函数其实就是组件本体了,这种写法就是所谓JSX语法,将组件中封装的html结构通过函数的return进行操,注意return的html结构需要包裹在一个()里面
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
//导出的就是一个组件,可以在页面中通过虚拟标签的方式调用,比如在刚才上面的如果文件中就有使用
export default App;
react组件的写法
上面我们可以看到函数式组件,react还支持一种类式组件,新建一个home.jsx,扩展名用js也行
import { Component } from "react";
export default class Home extends Component {
render(){
return (
<div>hahahaha</div>
)
}
}
然后在index.js入口文件中导入home并修改下render中渲染的虚拟DOM,我们可以看到一样可以正常渲染
现在我们可以把顶层组件相关的文件都删除掉,然后重写我们自己的顶层组件
扩展内容:JSX配置优化
现在我们在js里面写标签会发现一些快捷键都不好用了,我们在VScode中打开设置,搜索
include Language
、将搜索结果中点击添加项按钮,项配置为JavaScript,值配置为JavaScriptreact
再搜索trigger,找到Emmet: Trigger Expansion On Tab项勾选上
react组件编写的注意事项
1、return的标签结构中只能包含一个根标签(vue3可以支持多个根标签),同时react支持用没有标签名的标签作为根标签使用,如下
return (
<>
<div>hahahaha</div>
</>
)
2、return的标签结构中其实并不是真正的html标签,而是react的虚拟标签,所以是区别大小写的
3、类语法的类名和函数语法的函数名其实就可以理解成是组件作为虚拟标签使用的标签名,为了方便区别组件名作为虚拟标签名使用时,我们首字母大小,而组件内部return的虚拟标签我们采用小写
4、如果我们需要在虚拟标签的属性值中执行js语法,需要套用 { } 花括号
jSX语法糖
React采用JSX来替换常规的JavaScript语法,简单来说,JSX就是JavaScript+XML(可扩展标记语言)JSX是JavaScript的扩展,在React中JSX会被babel编译成JavaScript
举例说明:(把解构导入的Component换成导入整个React实例,因为我们要使用React的其他方法)
import React from "react";
export default class Home extends React.Component {
render(){
return (
<div>hahahaha</div>
)
}
}
按照上面我们说过的react组件编写的注意事项中的第三条,这里return的div标签其实并不是一个html标签,而是React创建的一个虚拟标签,所以其实际return的应该如下
import React from "react";
export default class Home extends React.Component {
render(){
return React.createElement(
"div", //标签名
null, //标签属性
"hahahaha" //标签内容
)
}
}
代码分析:
上面的代码就可以理解成JSX中虚拟标签div通过babel编译成js代码的一个情况,所以我们直接像上面这样写在React中也是一样可以实现渲染的
JSX语法的注意事项
因为React使用的是JSX语法,会在js中写入标签,而标签的使用就一定会涉及到标签属性的使用,所以这里我们需要注意,有一些常用的标签属性名与js中的关键字是一样的,所以就意味着会有冲突,所以在JSX中对于一些标签的属性使用做了一些调整
举例:
新建一个components文件夹存放组件,在内部新建一个one.jsx,然后再新建一个one.css导入到one.jsx
import './one.css' //导入使用在box上面的样式
function One(){
return (
<>
<div style={{color:'red'}}>我是第一个组件</div>
<div className="box">box</div>
<label htmlFor="userName">
用户名:
<input type="text" id="userName" />
</label>
</>
)
}
export default One;
把创建的one组件可以导入到顶层组件中,在顶层组件中调用
App.jsx
import { Component } from "react";
import One from './components/one'
export default class Home extends Component {
render(){
return (
<>
<One></One>
<div>hahahaha</div>
</>
)
}
}
代码分析:
style属性:添加行内样式的时候,样式属性名与值需要做成一个对象,这里style有两层{{ }} 需要分开理解,外层的{ } 表示在里面需要执行的是js语句,内层的{ } 是表示对象的大括号
className:因为现在的标签是写在js里面的,所以原本的class属性会与js中的用于声明类的class关键字冲突,所以改成了className
htmlFor:原本label中的for属性是可以指向一个表单的id值,但是循环使用的关键字也叫for,所以改成了htmlfor
为什么React不用原生的html而是要自己使用JSX虚拟标签来用
结论就是出于提升性能的角度来考虑的,我们可以看下以下代码,在index.js中添加如下代码
let HtmlDom = document.createElement("div"); //创建原生DOM元素(真实的html标签)
let ReactDom = React.createElement("div"); //创建react虚拟DOM(react虚拟的标签)
//把两个DOM都进行遍历查看内部结构的体量
for(let i in HtmlDom){
console.log("这是原生DOM的",i);
}
for(let i in ReactDom){
console.log("这是ReactDOM的",i);
}
代码分析:
从打印的结果我们就能看出来,原生的DOM比ReactDOM内部的体量相差巨大,ReactDOM内部只有7个属性,而原生DOM内部不计其数,单纯从体量的角度上来看就知道谁的性能更优