React 基础语法
第一章、react 介绍
Section titled “第一章、react 介绍”个人感觉,就是同 jsp形式上类似
-
- 声明式编程是目前整个大前端开发的模式:Vue、React、Flutter、SwiftUI;
- 它允许我们只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染我们的UI界面;
- 组件化、声明式、跨平台、响应式、虚拟DOM、通过jsx技术有更纯粹的
javaScripts语法
-
组件化开发页面目前前端的流行趋势,我们会将复杂的界面拆分成一个个小的组件;
-
-
2013年,
React发布之初主要是开发Web页面; -
2015年,
Facebook推出了ReactNative,用于开发移动端跨平台;(虽然目前Flutter非常火爆,但是还是有很多公司在使用ReactNative-);用开发跨平台移动端的适配方案——native 是原生的意思
-
- 2017年,
Facebook推出ReactVR,用于开发虚拟现实Web应用程序;(VR也会是一个火爆的应用场景);
-
React的开发依赖
Section titled “React的开发依赖”React开发依赖3个库-
react:包含react所必须的核心代码 -
react-dom:react渲染在不同平台所需要的核心代码,主要用于页面渲染 -
babel:将jsx转换成React,创建虚拟节点方法代码的工具如果使用
React.createElement来编写源代码,它编写的代码非常的繁琐和可读性差。让babel帮助我们将jsx转换成React.createElement。<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包中包含了reactweb和react-native所共同拥有的核心代码react-dom针对web和native所完成的事情不同web端:react-dom会将jsx最终渲染成真实的DOM,显示在浏览器中native端:react-dom会将jsx最终渲染成原生的控件(比如Android中的Button,iOS中的UIButton)。
-
html 使用
Section titled “html 使用”- 引入依赖库
- 重点:一定要设置
script标签的类型<script type="text/babel">- 就像 vue 中使用 jsx 一样,要添加
lang=‘jsx'
- 就像 vue 中使用 jsx 一样,要添加
一、react 渲染流程
Section titled “一、react 渲染流程”
react中是借助于babel解析的,相对与vue非常的简单,就是对应jsx生成React.createElement('div',{title: "zhangsan"}, "这里是内容")
vue中的解析,解析的过程中还需要一些指令进行处理
-
(1)、所以
jsx被babel转化之后 的代码就是,React.createElement(),相似于vue中的h()函数因此,可以直接使用
React.createElement()写react代码,但是可读性非常差 -
(2)、
React.createElement执行最终创建出来一个ReactElement对象,组成了一个JavaScript的对象树
JavaScript的对象树就是虚拟DOM(Virtual DOM)
- (3)、最后将虚拟dom,同步渲染成真实的dom,展示到页面上。
二、虚拟DOM的作用
Section titled “二、虚拟DOM的作用”-
可以快速的进行
diff算法,来决定哪些节点需要更新,哪些不需要更新 -
跨平台,
react-navtive -
通过虚拟
DOM将命令式编程转到了声明式编程的模式它是一个相对简单的
JavaScript对象 通过声明ReactDOM.render让虚拟DOM和 真实DOM同步起来,这个过程中称为更新 (patch),又被称为**“比对”(diffing)** 或**“协调”(reconciliation)**。- 只需要告诉
React希望让UI是什么状态 React来确保DOM和这些状态是匹配的- 不需要直接进行
DOM操作,就可以从手动更改DOM、属性操作、事件处理中解放出来
一个运行时渲染器将会遍历整个虚拟
DOM树,并据此构建真实的DOM树。这个过程被称为挂载 (mount)。 - 只需要告诉
三、react 响应式更新
Section titled “三、react 响应式更新”-
在
react中没有双向绑定的概念,每次更新页面和值都需要手动调用指定的api来触发 -
Section titled “React 只更新它需要更新的部分”React只更新它需要更新的部分尽管每次修改都会新建一个描述整个
dom的VNode,但只会更新实际改变了的内容的dom元素。- 会进行优化,子组件没发生变化的话,就只会重新生成当前组件的
VNode
- 会进行优化,子组件没发生变化的话,就只会重新生成当前组件的
-
React框架在接收到用户状态改变通知后,会根据当前渲染树,结合最新的状态改变,通过Diff算法,计算出树中变化的部分、自动且高效的同步到虚拟DOM,最后再批量同步到真实DOM中只更新变化的部分(DOM操作)。- 浏览器的重绘和回流都是比较昂贵的操作,如果每一次改变都直接对DOM进行操作,这会带来性能问题,而批量操作只会触发一次DOM更新。
- 而不是每次改变都去操作一下DOM。
- 从而避免整棵树重构,提高性能。
-
如果DOM只是外观风格发生变化,如颜色变化,会导致浏览器重绘界面。
-
如果DOM树的结构发生变化,如尺寸、布局、节点隐藏等导致,浏览器就需要回流(及重新排版布局)。
第二章、jsx 语法
Section titled “第二章、jsx 语法”
JSX是一种JavaScript的语法扩展(eXtension),也在很多地方称之为JavaScript XML,因为看起就是一段XML语法;
- jsx 用于描述我们的UI界面,将标签 和 JavaScript 融合在一起使用;
- 不需要专门学习模块语法中的一些指令(比如
v-for、v-if、v-else、v-bind) - 就是
js加html混在一起使用,就像是jsp,ejs
一、React为什么选择JSX
Section titled “一、React为什么选择JSX”
React认为像vue template模板语法那样,渲染逻辑本质上与其他UI逻辑存在内在耦合
- 简单说,模板语法 和
js之前存在很强的耦合性,实现业务逻辑上太依赖模板了,并没有jsx自由,js更好的实现思想,都要考虑模板
二、jsx 语法规范(重点)
Section titled “二、jsx 语法规范(重点)”-
jsx标签不能是字符串,都需要babel进行转换 -
react组件首字母必须大写因为
React中使用JSX语法引入组件的时候,是根据首字母是否大写来区分它react组件还是dom元素。 -
jsx只能有一个根,vue2也只能有一个根,vue3可以有多个根 -
通常使用分组运算符将换行的
jsx,当作一个整体 -
可以是双标签,单标签必须使用
/>结尾,例:img 标签,后面要加 / -
jsx中使用{}包裹js代码进行执行,注释也是一样{/* */} -
在子元素(可以理解为被jsx标签包裹的
{}) 的{}中如果存放的是数组的话,会将数组元素全部取出,直接显示。放的jsx标签的话也会显示 -
Number、String会直接显示 -
null、undefined、Boolean不会显示内容,必须要转换成字符传显示{ture.toString()}- 注意:但是元素会正常显示
//布尔类型需要转换成 String 之后才可以显示,不转化的话这里是个空标签 <div></div><div>{this.state.flag.toString()}</div> -
Object不能作为jsx标签内容,会报错
~~~typescript constructor() { super(); this.state = { argu3: {name: "zhangsan ", age: 98} } }
render() { return ( <div> {/* 会报错 <div>{this.state.argu3}</div> */} </div> ) }~~~11. {} 语法也可以嵌入表达式、运算表达式、三元运算符、执行一个函数。
-
render()函数当中返回的jsx内容( 注意:这里是jsx内容 ),就是之后React会帮助我们渲染的内容-
参数:要渲染的根组件
Section titled “参数:要渲染的根组件”要是 jsx 内容,或者 jsx 组件
Section titled “要是 jsx 内容,或者 jsx 组件”
-
三、jsx 绑定
Section titled “三、jsx 绑定”属性基本绑定
Section titled “属性基本绑定”- 属性绑定统一
{},例:title={}, 再次提示jsx{}不是字符串,
class绑定
Section titled “class绑定”-
class绑定{}+${} -
jsx 最后还是要转换为 js,由于
class是关键字,所以定义的时候要使用className替代 class,尽量避免冲突
<div> <button className={`${this.state.flag ? 'box' : ''}`} onClick={() => this.trigger()} > trigger </button> </div>style 绑定
Section titled “style 绑定”-
jsx中 不支持style字符串写法,style的值本质上又是一个对象,可以 直接给style属性赋值css属性对象 -
需要使用
Object写法之前提到的 ( 只是被标签元素包裹的 jsx内容 不支持
Object) -
注意:根据规范,这里的
{{}},并不是mustache语法
<button onClick={this.foo.bind(this)}> foo </button> <div style={ { width: "100px", height: "100px", backgroundColor: "green", //绑定样式 border: `${this.state.str}` } }> </div>第三章、React 的条件/列表渲染
Section titled “第三章、React 的条件/列表渲染”React中,所有的条件判断与列表渲染都和普通的JavaScript代码一致;简单来说就是js判断。
一、条件判断
Section titled “一、条件判断”1、if判断
Section titled “1、if判断”react 中的逻辑判断,就是普通的 if 语句
- 实现
v-show直接添加类即可
let showElement = null if (isReady) { showElement = <h2>准备开始比赛吧</h2> } else { showElement = <h1>请提前做好准备!</h1> }2、三元运算符
Section titled “2、三元运算符” <div>{ isReady ? <button>开始战斗!</button>: <h3>赶紧准备</h3> }</div>3、&&判断
Section titled “3、&&判断”应用场景:在状态中取出属性值的时候,有可能这个状态在初始化或者某些情况为
null/undefined的时候会报错,使用&&可以避免报错,等到真正有值的时候在去使用。
- 用的很多
- false 是不会显示的
<div>{ friend && <div>{friend.name + " " + friend.desc}</div> }</div>4、使用es11可选链进行判断
Section titled “4、使用es11可选链进行判断”二、列表渲染
Section titled “二、列表渲染”其实就是,使用for循环组装jsx
-
但更多的方式是使用,map组装 jsx 元素列表,直接通过
{}语法进行展示以为,jsx 数组当作,元素内容的时候,会直接将jsx元素取出,直接展示
-
例:
books.map((item, index) => {return (//key值,要添加,方便进行diff算法<tr key={item.id}>{item.name}</tr>)})
第四章、setState
Section titled “第四章、setState”开发中并不能直接通过修改state的值来让界面发生更新,
React并没有实现类似于Vue2中的
Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化
- 必须通过父组件
Component中的setState({})方法,来告知React数据已经发生了变化; - setState是一个合并的动作,没有修改的属性会保持
一、setState异步更新
Section titled “一、setState异步更新”setState是异步的操作,并不能在执行完setState之后立马拿到最新的state的结果。
setState异步的原因
Section titled “setState异步的原因”-
批量更新,提升性能
Section titled “批量更新,提升性能”如果每次调用
setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;-
获取到多个更新之后的值,之后进行批量更新
在同一个事件对列当中,会一次放置多个
setState,当前对列中的异步setState执行之后,在执行render函数。render会检查state和props中的属性,将被修改的值,批量同步到真实dom上,节省回流重绘的开销 -
据说render执行的时机,是和屏幕的刷率有关系,不一定会等当前对列异步事件执行完毕之后执行
-
-
保持 render 和 setState 修改的值保持一致性
Section titled “保持 render 和 setState 修改的值保持一致性”- 先明确
render不是和setState绑定到一起的 - 如果
setState为通过的话,获取到修改后的值,在计算一些逻辑的时候出现了异常,这时已经修改了的数据会和页面展示的数据会存在差异
- 先明确
setState的三种写法
Section titled “setState的三种写法”1、对象写法
Section titled “1、对象写法”- 一般不推荐,直接
this.state上修改属性,这样操作是没有SPU优化的。- 因此,下面第二次修改的 counter 的情况也不多见
//异步修改,state中的值。this.setState({counter: this.state.counter+1})/*由于是异步的,”且“ 函数执行“前”会将值赋值给形参(javaScript高级,函数的执行流程),因此在将参数对象赋值的时候,this.counter 还是上面 this.setSate 修改前的 this.counter*/this.setState({counter: this.state.counter+1})2、函数写法
Section titled “2、函数写法”传入回调函数写法
-
让代码实现更好的内聚性。
就是可以在回调函数中,写一些代码逻辑
-
会将 “上一次” 修改的
state和props,回传到 “下一次”setState的回调函数中
this.setState((state, props) => { //可以在这里添加一些代码逻辑 return {counter: this.state.counter+1}})
this.setState((state, props) => { //这里的state 中的 counter 已经被修了 return {counter: this.state.counter+1}})3、传入回调函数
Section titled “3、传入回调函数”setState在React的事件处理中是一个异步调用
- state 修改完成之后,会回调第二个参数传入函数
this.setState({message: "zhangsan"}, () => {})setState的同步写法
Section titled “setState的同步写法”-
在react18之 “前”
Section titled “在react18之 “前””setTimeout和 “原生dom回调” 中的setState操作, 是同步操作- 在组件声明周期函数,或者
React合成事件中( 就是react中的事件回调 ),是异步的
-
在react18之 “后”,
Section titled “在react18之 “后”,”- 默认所有的操作都放到了 “批处理” 中 都变成了异步操作(批处理)
-
如果在某些场景一定要同步的话可以使用
react-dom包 中的flushSync函数参数:
callbackimport { flushSync } from 'react-dom'flushSync(() => {this.setState({ message: "你好啊, 李银河" })})console.log(this.state.message)
hooks setState同步写法
Section titled “hooks setState同步写法”- 结合
useEffect第二个参数,依赖被修改之后自动回调
二、强制更新
Section titled “二、强制更新”this.forceUpdate()- 不会经常用,不会有scu优化
全局的origin