官网:https://zh-hans.reactjs.org/
React简单项目创建(React一)
React特点
- 声明书编程:只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染UI界面
- 组件化开发:将复杂的界面拆分为一个个小的组件
- 多平台适配:React(Web)、ReactNative(移动端平台)、ReactVR(虚拟现实Web应用程序)——虚拟DOM也对跨平台有很大用处
React开发依赖
- react:react所必须的核心代码
- react-dom:react渲染在不同平台上所需要的核心代码——虚拟DOM→真实DOM(浏览器)/原生控件(移动端)
- babel:将jsx转换为React代码的工具,如果直接用React.createElement来写React对象,可以不用babel,同时可以将ES6转换为ES5语法
react CDN引入:
1 | <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> |
React第一个Hello World
1 | <!-- root作为根节点--> |
注:
- script一定要设置 type=”text/babel” 否则不会被babel解析,jsx语法就不能识别
- ReactDom.createRoot()是创建一个React根,不一定是整个html的根
- render函数,参数是要渲染的组件
- {}语法可以引入JavaScript语法
React组件化开发
组件化开发:root.render参数是一个HTML元素或一个组件,那么可以将复杂的业务逻辑封装到一个组件中,然后传入到ReactDom.render中
React组件:
- 类组件与函数组件
- 根据内部是否有状态需要维护:无状态组件、有状态组件(this.state,不考虑hooks的情况下函数组件是无状态组件,而类组件不定义this.state也可以看做无状态组件)
- 根据组件的不同职责:展示型组件、容器型组件
1 | class App extends React.Component{ |
数据依赖
- 参与界面更新的数据:当数据改变时,需要更新组件渲染的数据(调用this.setState更新数据会自动检测改变的变量,并重新执行render函数更新页面)——参与数据流,放入当前对象的state对象中
- 不参与页面更新的数据:数据改变时,不需要更新页面的数据
事件绑定
this指向问题:
- babel默认严格模式,那么默认调用的函数的this为undefined
- 一般的button点击,this指向button本身,但是这里调用的button是一个React的Element对象,并不是页面中的button,是React内部调用响应函数,因此不知道如何绑定正确的this
绑定this方法:
bind方法:调用bind方法生成一个带特定this的函数赋值给onClick
1
<button onClick={this.changeText.bind(this)}>
箭头函数方法:如上面代码,给onClick赋值一个箭头函数,在箭头函数中调用隐式绑定想要运行的函数,箭头函数由于没有this,会向上寻找到this即class对象
事件参数传递:点击函数会传入一个event,可以将event与其他的参数放在箭头函数里面调用函数时传给最后的响应函数
1 | <li onClick={event=>this.clickLi(event,"oww","22")}>按钮</li> |
map映射
往往会从数据数组中得到要展示的Element列表,就可以使用map映射
1 | <div> |
JSX语法
1 | const element = <div>Hello World</div> |
类似于上诉代码的形式就是一个JSX代码
React选择JSX的理由:
React认为渲染逻辑本质上与其他UI逻辑存在耦合(UI需要绑定事件、UI需要展示数据状态、状态改变时,又会改变UI)
因为渲染逻辑与UI逻辑的耦合,React没有将标记分离到不同的文件中,而是组合在一起形成组件
注:JSX只能有一个根元素,也就是上面不能存在两个兄弟DIV,实在需要可以用数组[]包围,JSX中的单标签必须以/>结尾
JSX中的变量
- Number、String、Array可以直接显示
- null、undefined、Boolean内容为空,如确实要显示,转换为字符串后使用
- 嵌入表达式使用(运算表达式、三元运算符、执行函数——是一个函数的执行得到返回值)
- Object对象不能作为子元素
JSX绑定属性
- title属性/img的src属性/a元素href属性:直接使用title/src/href=””/{}
1 | const element = <h2 title="h2">哈哈哈</h2> |
- class属性:小驼峰法className设置
1 | const element = <h2 className={'abc cba ${isActive?'active':''}'}>哈哈哈</h2> |
- 内联style属性:style=””/{}设置——外层{}是JSX语法,里层{}是包裹对象,font-size要用小驼峰法fontSize
1 | const element= <h2 style={{color:"red", fontSize:"30px"}}>哈哈哈</h2> |
JSX本质
JSX实际上是React.createElement的语法糖,下面两种方法等效,label会将JSX转换为React对象
1 | const element = React.createElement('div',{class:"active",style={color:"red"}},children) |
虚拟DOM
通过React.createElement最终可以创建出一个ReactElement对象,其与其子元素构成一个对象树,这个树就是虚拟DOM
React从JSX到真实DOM的流程:
虚拟DOM帮助实现声明式编程
虚拟DOM:虚拟DOM是一种编程理念
- UI以一种虚拟化的方式保存在内存中,是一个较为简单的JavaScript对象
- 通过ReactDom.render函数让虚拟DOM与真实DOM同步起来,这一个步骤叫做协调
- 更新状态后整体刷新,而不是原生的局部刷新
Diff算法:如果简单的整体刷新会导致项目运行效率较低
- Diff算法对于没有改变的DOM节点,保持原样不动,仅仅创建并替换变更过的DOM节点,实现DOM节点复用
- 因此需要实现DOM节点的版本控制,如果对原生的DOM节点进行版本控制,会有大量的DOM查询操作,所以React将DOM的diff操作转移到轻量js对象上,可以避免大量的DOM操作,这个轻量的js对象就是虚拟DOM
实现过程:
- 维护一个使用JS对象表示的虚拟DOM,与真实DOM一一对应
- 对前后的虚拟DOM做diff操作,找到变化的虚拟DOM
- 将变化的DOM应用于真实DOM(不是不操作DOM,而是对DOM的操作次数降到最低)
React的声明式编程
- 通过虚拟DOM表示希望UI是什么状态
- React确保DOM和这些状态匹配
- 不需要直接进行DOM操作,而去改变虚拟DOM,从手动更改DOM、属性操作、事件处理中解放出来(传统的DOM API太多,操作复杂,容易出现Bug,代码不易维护),用户只需要关心状态和最终的UI样式