0%

ReactDay1—Intro

React小试

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
32
33
34
35
// 使用组件重构  
//类组件和函数组件
<script type="text/babel">
class App extends React.Component {
//组件数据
constructor() {
super();
this.state = {
message: "hello wolrd",
name: "why"
};
}

//组件方法
btnClick() {
//setState内部完成两件事:1.将message修改 2.自动执行render
this.setState({
message: "hello react"
})
}

//渲染内容render
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.btnClick.bind(this)}>修改文本</button>
//注意必须绑定好this
</div>
)
}
}

const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(<App/>)

循环写法

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
<script type="text/babel">
const root = ReactDOM.createRoot(document.querySelector("#root"))

class App extends React.Component {
constructor() {
super()

this.state = {
movies: ["xixi","haha", "zeze"]
}
}

render() {
return (
<div>
<h2>Movie List</h2>
<ul>
{this.state.movies.map(movie => <li>{movie}</li>)}
</ul>
</div>
)
}
}


root.render(<App/>)

JSX书写规范

  • jsx结构中只能有一个根元素

  • jxs结果通常会包裹一个(),将jsx当做一个整体实现换行

  • 标签可以是单标签,但必须以/>结尾

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    render() {
    const { message } = this.state

    return (
    <div>
    <h2>{message}</h2>
    <br/>
    </div>
    )
    }

jsx的使用

jsx嵌入变量作为子元素

  • case1:Number, String, Array类型时,可以直接显示

  • case2:null,undefined,Boolean类型时,内容为空

    如果希望可以显示null,undefined,boolean那么需要转成字符串(调toString,或+””)

  • case3:Object对象类型不能作为子元素

  • case4:可以插入表达式(运算表达式,三元运算符,执行一个函数)

基本属性绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class App extends React.Component {
constructor() {
super()
this.state = {
title:"hahaa",
imgURL: "xxxx"
}
}

render() {
const { title,imgURL } = this.state
return (
<div>
<h2 title={title}>I'm h2</h2>
<img src={imgURL} />
</div>
)
}
}

类绑定

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
<script type="text/babel">
class App extends React.Component {
constructor() {
super()
this.state = {
isActive: true,
objStyle:{color:"red", fontsize:"30px"}
}
}

render() {
//需求isActive:true -> active
const { isActive, objStyle } = this.state
//方式1
const className = `abc cba ${isActive ? 'active':''}`
//方式2:
const classList = ["abc", "cba"]
if(isActive) classList.push("active")
//方式3 使用classnames

return (
<div>
<h2 className={className}>I'm h2</h2>
<h2 className={classList.join(" ")}>I'm h2</h2>

<h2 style={objStyle}></h2>
</div>
)
}

React事件绑定

三种方式解决this问题

  • bind给btnClick显示绑定this
  • 使用ES6 class fields语法
  • 事件监听时传入箭头函数(最优)
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
32
33
34
35
36
37
38
39
40
<script type="text/babel">
class App extends React.Component {
constructor() {
super()
this.state = {
message:"hello world",
counter:1000
}
this.btn1Click = this.btn1Click.bind(this)
}

btn1Click() {
console.log("btn1Clik", this);
this.setState({counter: this.state.counter+1})
}

btn2Click = () => {
console.log("btn2Clik", this);
this.setState({counter: 1000})
}

btn3Click() {
console.log("btn3", this);
this.setState({counter: 3})
}
render() {
const { message } = this.state
return (
<div>
{/* 方式一:bind绑定*/}
<button onClick={this.btn1Click}>按钮1</button>
{/* 方式二:ES6 class fields*/}
<button onClick={this.btn2Click}>按钮2</button>
{/* 方式三:直接传入一个箭头函数*/}
<button onClick={() => this.btn3Click()}>按钮3</button>
<h2>当前计数:{this.state.counter}</h2>
</div>
)
}
}

基本参数传递

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
class App extends React.Component {
constructor() {
super()
this.state = {
message:"hello world",
}
}

btnClick(event, name, age) {
console.log("btnClick", event, this);
console.log(name, age);
}

render() {
return (
<div>
{/* event参数的传递*/}
<button onClick={this.btnClick.bind(this)}>按钮1</button>
<button onClick={(event) => this.btnClick(event)}>按钮2</button>

{/*额外的参数传递*/}
<button onClick={(event) => this.btnClick(event, "why", 18)}>按钮</button>
</div>
)
}
}

条件渲染

  • 条件判断
  • 三元运算
  • 与运算&&
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
32
33
34
class App extends React.Component {
constructor() {
super()
this.state = {
message:"hello world",
isReady: false,
friend:{
name:"kobe",
desc:"xixihaha"
}
}
}

render() {
const { isReady,friend } = this.state
let showElement = null
if (isReady) {
showElement = <h2>开始战斗</h2>
} else {
showElement = <h2>做好准备</h2>
}
return (
<div>
{/*方式一:根据条件给变量赋不同的内容*/}
<div>{showElement}</div>
{/*方式二 :三元运算*/}
<div>{isReady ? <button>开始战斗</button>:<h2>做好准备</h2>}</div>
{/*方式三 :&&逻辑与运算*/}
{/*friend没取到值时为null,就不显示,取到了再显示*/}
<div>{ friend && <div>{friend.name+" "+friend.desc}</div>}</div>
</div>
)
}
}

列表渲染

展示:map

过滤:filter

截取数组:slice

注意每个列表的子元素需要添加一个key

  • 主要是提高diff算法的效率
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
32
33
34
35
36
class App extends React.Component {
constructor() {
super()
this.state = {
students:[
{id:111,name:"haha", score:12},
{id:222, name:"yy", score:13},
{id:333,name:"xxx", score:9},
{id:444,name:"a12", score:14},
]
}
}

render() {
const { students } = this.state
// const filterStudents = students.filter(item => {
// return item.score>10
// })
// const sliceStudents = filterStudents.slice(0,2)
return (
<div>
<h2>学生列表数据</h2>
<ul>{
Students.filer(item => item.score >10).slice(0,2).map(item => {
return (
<div class="item" key={item.id}>
<h2>学号:{item.id}</h2>
<h2>姓名:{item.name}</h2>
<h2>分数:{item.score}</h2>
</div>
)
})}
</ul>
</div>
)
}

JSX的本质

可以通过Babel官网查看

jsx其实就React.createElement(component, props, …children)函数的语法糖

  • 所有的jsx最终都会被转换成React.createElement的函数调用

createElement需要传递三个参数

  • type:
    • 当前ReactElement的类型
    • 如果是标签元素,那么就使用字符串表示’div’
    • 如果是组件元素,那么就直接使用组件的名称
  • config:
    • 所有jsx中的属性都在config以对象的属性和值的形式存储
    • 比如传入className作为元素的class
  • children
    • 存放在标签中的内容,以children数组的方式进行存储

虚拟DOM

通过React.createElement最终创建出来一个ReactElement对象

这个对象组成了一个JS的对象树,也就是虚拟DOM

目的:传统Web会把数据的变化时时刚更新到用户界面,每次微小的变动都会引起DOM树重新渲染

虚拟DOM是将所有操作累加起来,基于diff算法,统计计算出所有变化后,统一更新一次DOM.虚拟DOM还可以做到跨平台,利用REACT渲染到Web端,利用其他的可以渲染到ios端

购物车案例

值得注意点:

  • 数量的增删可以抽取到一个事件,通过加+1或-1来实现增删
  • 条件渲染时,可以尝试代码抽取到两个函数,一个购物车不为空,购物车为空,最后在render通过一个三元运算来决定
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  class App extends React.Component {
constructor() {
super()
this.state = {
message:"hello world",
books:books
}
}

changeCount(index, count) {
const newBooks = [...this.state.books]
newBooks[index].count += count
this.setState({ books: newBooks })
}

removeItem(index) {
const newBooks = [...this.state.books]
newBooks.splice(index, 1)
this.setState({books: newBooks})
}

renderBookList() {
const { books } = this.state
const totalPrice = books.reduce((preValue, item) => {
return preValue + item.count * item.price
},0)
return <div>
<table>
<thead>
<tr>
<th>序号</th>
<th>名称</th>
<th>日期</th>
<th>价格</th>
<th>数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{
books.map((item,index) => {
return (
<tr key={item.id}>
<td>{index+1}</td>
<td>{item.name}</td>
<td>{item.date}</td>
<td>{item.price}</td>
<td>
<button onClick={() => this.changeCount(index,-1)} disabled={item.count <= 1}>-</button>
{item.count}
<button onClick={() => this.changeCount(index, 1)}>+</button>
</td>
<td><button onClick={() => this.removeItem(index)}>删除</button></td>
</tr>
)
})
}
</tbody>
</table>
<h2>总价格:{totalPrice}</h2>
</div>
}

renderBookEmpty() {
return <div><h2>购物车空</h2> </div>
}

render() {
const { books } = this.state
return books.length ? this.renderBookList() : this.renderBookEmpty()
}

}
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App/>)
</script>
-------------本文结束感谢您的阅读-------------