一. React
的介绍和特点
1.React
的介绍(技术角度)
React
是什么?React
:用于构建用户界面的 JavaScript 库React
的官网文档:https://zh-hans.reactjs.org/

2.React
的特点 – 声明式编程
- 声明式编程:
- 声明式编程是目前整个大前端开发的模式:
Vue
、React
、Flutter
、SwiftUI
- 它允许我们只需要维护自己的状态,当状态改变时,
React
可以根据最新的状态去渲染我们的UI
界面
- 声明式编程是目前整个大前端开发的模式:

3.React
特点 – 组件化开发
- 组件化开发:
- 组件化开发页面目前前端的流行趋势,我们会将复杂的界面拆分成一个个小的组件
- 如何合理的进行组件的划分和设计也是后面我会讲到的一个重点

4.React
的特点 – 多平台适配
- 多平台适配:
- 2013,React发布之初主要是开发
Web
页面 - 2015,
Facebook
推出了ReactNative
,用于开发移动端跨平台(虽然目前Flutter
非常火爆,但是还是有很多公司在使用ReactNative
) - 2017,
Facebook
推出ReactVR
,用于开发虚拟现实Web
应用程序;(VR
也会是一个火爆的应用场景)
- 2013,React发布之初主要是开发

二. React
开发依赖分析
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
)
2.Babel
和React
的关系
babel
是什么呢?Babel
,又名Babel.js
- 是目前前端使用非常广泛的编译器、转移器
- 比如当下很多浏览器并不支持
ES6
的语法,但是确实ES6
的语法非常的简洁和方便,我们开发时希望使用它 - 那么编写源码时我们就可以使用
ES6
来编写,之后通过Babel
工具,将ES6
转成大多数浏览器都支持的ES5
的语法
React
和Babel
的关系:- 默认情况下开发
React
其实可以不使用babel
- 但是前提是我们自己使用
React.createElement
来编写源代码,它编写的代码非常的繁琐和可读性差 - 那么我们就可以直接编写
jsx(JavaScript XML)
的语法,并且让babel
帮助我们讲jsx
代码转换成React.createElement
- 后续还会详细讲到
- 默认情况下开发
3.React
的依赖引入
所以,我们在编写
React
代码时,这三个依赖都是必不可少的那么,如何添加这三个依赖:
- 方式一:直接CDN引入
- 方式二:下载后,添加本地依赖
- 方式三:通过npm管理(后续脚手架再使用)
暂时我们直接通过CDN引入,来演练下面的示例程序:
- 这里有一个crossorigin的属性,这个属性的目的是为了拿到跨域脚本的错误信息
html
<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>
三. Hello React
案例
- 为了演练
React
,我们可以提出一个小的需求:- 在界面显示一个文本:
Hello World
- 点击下方的一个按钮,点击后文本改变为
Hello React
- 在界面显示一个文本:

- 当然,你也可以使用
jQuery
和Vue
来实现,甚至是原生方式来实现,对它们分别进行对比学习
1.Hello World
- 第一步:在界面上通过
React
显示一个Hello World
- 注意:这里我们在
script
标签中编写React
代码,必须添加type="text/babel"
,作用是可以让babel
解析jsx
的语法
- 注意:这里我们在

ReactDOM. createRoot
函数:用于创建一个React
根,之后渲染的内容会包含在这个根中- 参数:将渲染的内容,挂载到哪一个
HTML
元素上- 这里我们已经提定义一个
id
为app
的元素
- 这里我们已经提定义一个
- 参数:将渲染的内容,挂载到哪一个
root.render
函数:- 参数:要渲染的根组件
我们可以通过
{}
语法来引入外部的变量或者表达式react18
之前使用的是ReactDOM.render
函数html<div id="root"></div> <script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script type="text/babel"> // js代码如下 </script>
js
jsxconst rootEl = document.querySelector('#root') ReactDOM.render( <h2>hello world</h2>, rootEl )
2.Hello React
– 错误做法

3.Hello React
– 正确做法

四. React
组件化的封装
1.Hello React
– 组件化开发
整个逻辑其实可以看做一个整体,那么我们就可以将其封装成一个组件:
root.render
接收的参数可以是一个html
元素或一个组件- 所以我们可以先将之前的业务逻辑封装到一个组件中,然后传入到
ReactDOM.render
函数中的第一个参数
在
React
中,如何封装一个组件呢?这里我们暂时使用类的方式封装组件:- 1.定义一个类,继承自
React.Component
- 2.实现当前类组件的
render
函数render
函数返回的jsx
内容,就是之后React
会帮助我们渲染的内容
- 1.定义一个类,继承自
注意: 组件名称必须以大写字母开头
React
会将以小写字母开头的组件视为原生DOM
标签。例如,<div />
代表HTML
的div
标签,而<Welcome />
则代表一个组件,并且需在作用域内使用Welcome
jsxclass App extends React.Component { render() { return <h2>hello world</h2> } } const root = ReactDOM.createRoot(document.querySelector('#root')) root.render(<App/>)
2.组件化 - 数据依赖
组件化问题一:数据在哪里定义?
在组件中的数据,我们可以分成两类:
- 参与界面更新的数据:当数据变化时,需要更新组件渲染的内容
- 不参与界面更新的数据:当数据变化时,不需要更新将组建渲染的内容
参与界面更新的数据我们也可以称之为是参与数据流,这个数据是定义在当前对象的
state
中- 我们可以通过在构造函数中
this.state = { 定义的数据 }
- 当我们的数据发生变化时,我们可以调用
this.setState
来更新数据,并且通知React
进行update
操作- 在进行
update
操作时,就会重新调用render
函数,并且使用最新的数据,来渲染界面
- 在进行
- 我们可以通过在构造函数中
注意:
this.setState
方法是继承自React.Component
的实例方法- 调用
this.setState()
会对当前this
对象中的state
中值进行一个修改,并且重新执行render
函数- 重新执行
render
函数,会对有变化的数据重新生成一个虚拟DOM
,然后通过diff
算法来更新真实DOM
React
内部没有对state
数据做一个劫持,所以数据是没有响应式的,需要通过this.state
来更新状态(类似于小程序的this.setData
)- 而
Vue
中是有对data
中的数据做一个劫持,所以当数据发生改变时,会自动执行render
函数
- 重新执行
reactcomponent.forceUpdate(callback)
默认情况下,当组件的
state
或props
发生变化时,组件将重新渲染。如果render()
方法依赖于其他数据,则可以调用forceUpdate()
强制让组件重新渲染
五. React
数据事件处理
组件化问题二:事件绑定中的
this
- 在类中直接定义一个函数,并且将这个函数绑定到元素的
onClick
事件上,当前这个函数的this
指向的是谁呢?
- 在类中直接定义一个函数,并且将这个函数绑定到元素的
默认情况下是
undefined
- 很奇怪,居然是
undefined
- 因为在正常的
DOM
操作中,监听点击,监听函数中的this
其实是节点对象 - 这是因为
React
并不是直接渲染成真实的DOM
,我们所编写的button
只是一个语法糖,它的本质是React
的Element
对象 - 那么在这里发生监听的时候,
React
在执行函数时并没有绑定this
,默认情况下就是一个undefined
- 很奇怪,居然是
为什么默认是
undefined
呢?React
内部就是将该引用传递给一个对象中,如下:jsxclass App extends React.Component { changeText() { console.log(this) } render() { return ( <div> <h2>{ this.state.message }</h2> <button onClick={ this.changeText }>改变文本</button> </div> ) } } // 1. React内部对render方法返回的元素中所绑定的事件,并没有做一个对应的this绑定,而是将函数的引用传递了过去 const btnEvents = { onClick: this.changeText } React.creatElement('button', btnEvents) // 2. 然后当该button触发事件时,默认调用对应的回调函数 const click = btnEvents.onClick click()
而默认调用的函数中的
this
在普通环境下是window
,严格环境是undefined
,通过babel
转化后的代码都是在严格环境下的,所以就导致了默认是undefined
这种情况的出现
我们在绑定的函数中,可能想要使用当前对象,比如执行
this.setState
函数,就必须拿到当前对象的this
- 我们就需要在传入函数时,给这个函数直接绑定
this
- 类似于如下写法:
jsxclass App extends React.Component { constructor() { super() this.changeText = this.changeText.bind(this) // 写法二 } changeText() { console.log(this) } // 写法三: class 的 field,ES13中,新增了定义class类中成员字段field的其他方式 changeText = () => { console.log(this) } render() { return ( <div> {/* 写法一 */} <button onClick={ this.changeText.bind(this) }>改变文本</button> {/* 写法四 */} <button onClick={ () => this.changeText() }>改变文本</button> </div> ) } }
- 我们就需要在传入函数时,给这个函数直接绑定
六. React
其他案例实现
1.电影列表展示

2.计数器案例
