一. 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-nativereact包中包含了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.计数器案例

