0%

搭建一个React项目及React基础

官网: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
2
3
<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第一个Hello World

1
2
3
4
5
6
7
<!-- root作为根节点-->
<div id="root"></div>
<script type="text/babel">
const message = "hello World"
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<h2>{message}</h2>)
</script>

注:

  • 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class App extends React.Component{
constructor(){
super()
this.state = {
movies:["盗梦空间","星际穿越","大话西游","流浪地球"],
currentIndex: 0
}
}
clickLi(event,index){
this.setState({currentIndex:index})
}
render(){
return (
<div>
{this.state.movies.map((item,index)=>{
return(
<li
key={item}
onClick={(event)=>{
this.clickLi(event,index)
}}
className = {index===this.state.currentIndex?"active":""}>{item}
</li>
)
})}
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App/>)

数据依赖

  • 参与界面更新的数据:当数据改变时,需要更新组件渲染的数据(调用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
2
3
4
5
6
7
8
9
10
11
12
13
<div>
{this.state.movies.map((item,index)=>{
return(
<li
key={item}
onClick={(event)=>{
this.clickLi(event,index)
}}
className = {index===this.state.currentIndex?"active":""}>{item}
</li>
)
})}
</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
2
const element = React.createElement('div',{class:"active",style={color:"red"}},children)
const element = <div className = "active" style={{color:"red"}}>children1,children2</div>

虚拟DOM

  • 通过React.createElement最终可以创建出一个ReactElement对象,其与其子元素构成一个对象树,这个树就是虚拟DOM

  • React从JSX到真实DOM的流程:

    image-20230324165543425

虚拟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样式