文章目录
- 一、React是什么
- 二、React数据对比
- 三、React特点
- 3.1 技术特点
- 3.2 声明式编程
- 3.3 组件化开发
- 3.4 多平台适配
- 四、React开发依赖
- 4.1 React的开发依赖
- 4.2 Babel和React的关系
- 4.3 React的依赖引入
- 五、React初体验
- 5.1 Hello World
- 5.2 增加按钮,点击修改文本
- 5.3 组件化开发
- 5.5 组件化开发之数据依赖
- 5.5 组件化开发之事件绑定
- 5.6 版本16与18的小区别
- 5.7 案例:电影列表
- 5.8 案例:计数器
一、React是什么
- 相信每个做开发的人对它都或多或少有一些印象
- 我们来看一下官方对它的解释
用于构建用户界面的 JavaScript 库
- 中文官网文档
目前对于前端开发来说,几乎很少直接使用原生的JavaScript
来开发应用程序,而是选择一个JavaScript库(框架)
。
- 在过去的很长时间内,
jQuery
是被使用最多的JavaScript
库 - 在过去的一份调查中显示,全球前10,000个访问最高的网站中,有
65%
使用了jQuery
,是当时最受欢迎的JavaScript
库,但是,目前甚至已经处于淘汰的边缘了
二、React数据对比
而无论是国内外,最流行的其实是三大框架:Vue、React、Angular
,如下:
框架Google指数对比:
NPM下载量对比:
Github数据对比:
三、React特点
3.1 技术特点
React
由Facebook
来更新和维护,它是大量优秀程序员的思想结晶:
React
的流行不仅仅局限于普通开发工程师对它的认可;- 大量流行的其他框架借鉴
React
的思想;
Vue.js
框架设计之初,有很多的灵感来自Angular和React
。
- 包括
Vue3
很多新的特性,也是借鉴和学习了React
- 比如
React Hooks
是开创性的新功能 Vue Composition API
学习了React Hooks
的思想
Flutter
的很多灵感都来自React
:
- 事实上
Flutter中的Widget – Element – RenderObject
- 对应
React的就是JSX – 虚拟DOM – 真实DOM
所以React可以说是前端的先驱者,它总是会引领整个前端的潮流。
3.2 声明式编程
- 声明式编程是目前整个大前端开发的模式:
Vue、React、Flutter
- 允许我们只需要维护自己的状态,当状态改变时,
React
可以根据最新的状态去渲染我们的UI
界面;
3.3 组件化开发
- 组件化开发页面目前前端的流行趋势,我们会将复杂的界面拆分成一个个小的组件;
- 如何合理的进行组件的划分和设计也是一个重点;
3.4 多平台适配
- 2013年,
React
发布之初主要是开发Web
页面; - 2015年,
Facebook
推出了ReactNative
,用于开发移动端跨平台 - 2017年,
Facebook
推出ReactVR
,用于开发虚拟现实Web应用程序
四、React开发依赖
4.1 React的开发依赖
开发React
必须依赖三个库:
react
:包含react
所必须的核心代码
-react-dom
:react
渲染在不同平台所需要的核心代码babel
:将jsx
转换成React
代码的工具
第一次接触React
会被它繁琐的依赖搞蒙,居然依赖这么多东西:
- 对于
Vue
来说,我们只是依赖一个vue.js
文件即可,但是react
居然要依赖三个包 - 其实呢,这三个库是各司其职的,目的就是让每一个库只单纯做自己的事情;
- 在
React
的0.14
版本之前是没有react-dom
这个概念的,所有功能都包含在react
里;
为什么要进行拆分呢?原因就是react-native
。
react
包中包含了react web
和react-native
所共同拥有的核心代码。react-dom
针对web
和native
所完成的事情不同:
✓web端
:react-dom
会将jsx
最终渲染成真实的DOM
,显示在浏览器中
✓native端
:react-dom
会将jsx
最终渲染成原生的控件(比如Android中的Button,iOS中的UIButton)
4.2 Babel和React的关系
Babel是什么呢?
Babel
又名Babel.js
- 是目前前端使用非常广泛的编译器、转移器
- 比如当下很多浏览器并不支持
ES6
的语法,但是确实ES6
的语法非常的简洁和方便,我们开发时希望使用它 - 那么编写源码时我们就可以使用
ES6
来编写,之后通过Babel
工具,将ES6
转成大多数浏览器都支持的ES5
的语法
React和Babel的关系:
- 默认情况下开发
React
其实可以不使用babel
- 但是前提是我们自己使用
React.createElement
来编写源代码,它编写的代码非常的繁琐和可读性差 - 那么我们就可以直接编写
jsx(JavaScript XML)
的语法,并且让babel
帮助我们转换成React.createElement
4.3 React的依赖引入
所以,我们在编写React
代码时,这三个依赖都是必不可少的。
那么,如何添加这三个依赖:
- 方式一:直接
CDN
引入 - 方式二:下载后,添加本地依赖
- 方式三:通过
npm
管理(后续脚手架再使用)
◼ 暂时我们直接通过CDN
引入,来完成示例程序
ps: 这里有一个crossorigin的属性,这个属性的目的是为了拿到跨域脚本的错误信息
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
五、React初体验
5.1 Hello World
在界面上通过React
显示一个Hello World
,代码如下:
<body>
<div id="root"></div>
<!-- 加载 React。-->
<!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"。-->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
// ReactDOM.render(<h2>Hello World</h2>, document.querySelector('.root'))
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<h2>Hello React18</h2>)
</script>
</body>
ReactDOM.createRoot
函数:用于创建一个React
根,之后渲染的内容会包含在这个根中- 参数:将渲染的内容,挂载到哪一个
HTML
元素上,这里我们已经提定义一个id为app的div
- 参数:将渲染的内容,挂载到哪一个
- root.render函数:
- 参数:要渲染的根组件
- 可以通过
{}
语法来引入外部的变量或者表达式 - 这里我们编写
React
的script
代码中,必须添加type="text/babel"
,作用是可以让babel
解析jsx
的语法。
5.2 增加按钮,点击修改文本
新增按钮,点击后修改message
的值,代码如下:
<div id="root"></div>
<script type="text/babel">
let message = 'hello world'
const root = ReactDOM.createRoot(document.querySelector("#root"))
function changeMessage(){
message = 'hello react'
root.render(
<div>
<h2>{message}</h2>
<button onClick={changeMessage}>点我</button>
</div>
)
}
root.render(
<div>
<h2>{message}</h2>
<button onClick={changeMessage}>点我</button>
</div>
)
</script>
5.3 组件化开发
整个逻辑其实可以看做一个整体,那么我们就可以将其封装成一个组件:
- 我们说过
root.render
参数是一个HTML
元素或者一个组件 - 所以我们可以先将之前的业务逻辑封装到一个组件中,然后传入到
ReactDOM.render
函数中的第一个参数
在React
中,如何封装一个组件呢?这里我们暂时使用类的方式封装组件:
- 定义一个类(类名大写,组件的名称是必须大写的,小写会被认为是
HTML
元素),继承自React.Component
- 实现当前组件的render函数,
render
当中返回的jsx
内容,就是之后React
会帮助我们渲染的内容
5.5 组件化开发之数据依赖
在组件中的数据,我们可以分成两类:
- 参与界面更新的数据:当数据变量时,需要更新组件渲染的内容
- 不参与界面更新的数据:当数据变量时,不需要更新将组建渲染的内容;
参与界面更新的数据我们也可以称之为是参与数据流
,这个数据是定义在当前对象的state
中
- 我们可以通过在构造函数中
this.state = {定义的数据}
- 当我们的数据发生变化时,我们可以调用
this.setState
来更新数据,并且通知Reac
进行update
操作 - 在进行
update
操作时,就会重新调用render
函数,并且使用最新的数据,来渲染界面
5.5 组件化开发之事件绑定
事件绑定中的this
===>在类中直接定义一个函数,并且将这个函数绑定到元素的onClick事件上,当前这个函数的this
指向的是谁呢?
默认情况下是undefined
- 很奇怪,居然是
undefined
- 因为在正常的
DOM
操作中,监听点击,监听函数中的this
其实是节点对象(比如说是button
对象) - 这次因为
React
并不是直接渲染成真实的DOM
,我们所编写的button
只是一个语法糖,它的本质React的Element
对象; - 那么在这里发生监听的时候,
react
在执行函数时并没有绑定this
,默认情况下就是一个undefined
- 我们在绑定的函数中,可能想要使用当前对象,比如执行
this.setState
函数,就必须拿到当前对象的this
- 我们就需要在传入函数时,给这个函数直接绑定
this
类似于下面的写法:
当然也可以在组件的构造函数中对方法进行绑定,如下:
5.6 版本16与18的小区别
<script type="text/babel">
// 编写React代码(jsx语法)
// jsx语法 -> 普通的JavaScript代码 -> babel
// 渲染Hello World
// React18之前: ReactDOM.render
ReactDOM.render(<h2>Hello World</h2>, document.querySelector("#root"))
// React18之后:
const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(<h2>Hello World</h2>)
</script>
5.7 案例:电影列表
<body>
<!-- 加载 React。-->
<!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"。-->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
class AppMain extends React.Component {
constructor() {
super()
this.state = {
movies: ['大话西游', '功夫', '西游降魔', '赌圣']
}
}
render() {
return (
<div>
<h2>电影列表</h2>
<ul>
{this.state.movies.map(item => {
return <li>{item}</li>
})}
</ul>
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(
<AppMain />
)
</script>
</body>
5.8 案例:计数器
<body>
<!-- 加载 React。-->
<!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"。-->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
class AppMain extends React.Component {
constructor() {
super()
this.state = {
count: 100
}
this.add = this.add.bind(this)
this.sub = this.sub.bind(this)
}
add() {
this.setState({
count: this.state.count + 1
})
}
sub() {
this.setState({
count: this.state.count - 1
})
}
render() {
let { count } = this.state
return (
<div>
<h2>当前数值:{count}</h2>
<button onClick={this.add}>点我+1</button>
<button onClick={this.sub}>点我-1</button>
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(
<AppMain />
)
</script>
</body>