React 学习(一)

JSX语法

简单的jsx示例:

1
2
3
4
5
6
7
8
import React, {Component} from 'react'

class JSX extends Component{
render() {
return <div>jsx语法</div>
}
}
export default JSX

jsx语法中 return后面不能有双引号或单引号,并且必须被包含在一个大的根节点中

典型错误示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, {Component} from 'react'

class JSX extends Component{
render() {
return (
<div>jsx语法</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
)
}
}
export default JSX

如何解决:

外层引入一个div标签或者Fragment占位符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, {Component, Fragment} from 'react'

class JSX extends Component{
render() {
return (
<Fragment>
<div>jsx语法</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</Fragment>
)
}
}
export default JSX

推荐使用Fragment, 推荐使用Fragment占位符不生成任何虚拟dom节点

React中的响应式设计思想和事件绑定

事件绑定

看一个小例子,给input框赋值一个默认值,并能够根据输入改变默认值

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
import React, {Component, Fragment} from 'react'
class TodoList extends Component{
constructor(props) {
super(props)
this.state = {
inputValue: "hello!!!!!",
list: [],
}
}
render() {
return (
<Fragment>
<div>
<input
value={this.state.inputValue}
onChange={this.handleInputChange.bind(this)}
/>
<button>提交</button>
</div>
<ul>
<li>学英语</li>
<li>learn react</li>
</ul>
</Fragment>
)
}
handleInputChange(e) {
this.state.inputValue = e.target.value;
}
}
export default TodoList

代码分析:首先程序初始化的时候inputValue为”hello!!!!!”,render函数执行的时候把input的内容渲染成数据里面inputValue的值
然后给input绑定了一个onchange事件,同时用es6的bind方法传递react的this对象到handleInputChange中,在handleInputChange去
改变state中inputValue的值为手动输入的对象

实现一个todolist

todolist新增功能

利用在React中state数据变化dom也会变化的特性:

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
import React, {Component, Fragment} from 'react'

class TodoList extends Component{
constructor(props) {
super(props);
this.state = {
inputValue: "",
list: [],
}
}
render() {
return (
<Fragment>
<div>
<input
value={this.state.inputValue}
onChange={this.handleInputChange.bind(this)}
/>
<button onClick={this.handleButtonClick.bind(this)}>提交</button>
</div>
<ul>
{
this.state.list.map((item, index) => {
return <li>{item}</li>
})
}
</ul>
</Fragment>
)
}
handleInputChange(e) {
this.setState({
inputValue: e.target.value,
});
}
handleButtonClick(e) {
this.setState({
list: [...this.state.list, this.state.inputValue],
inputValue: "",
});
}
}
export default TodoList

Warning: Each child in an array or iterator should have a unique “key” prop. 错误问题
es5的map方法中必须指定一个key值否则会报错

1
2
3
4
5
6
7
<ul>
{
this.state.list.map((item, index) => {
return <li key={index}>{item}</li>
})
}
</ul>

todolist删除功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<ul>
{
this.state.list.map((item, index) => {
return <li
key={index}
onClick={this.handleDelete.bind(this, index)}
>{item}</li>
})
}
</ul>
handleDelete (index) {
//immutable
//state不允许我们做任何的改变,对react性能优化有影响
const list = [...this.state.list];
list.splice(index, 1)
this.setState({
list: list
})
}

在handleDelete方法中,不推荐使用this.state.list.splice(index, 1),原因见注释

label属性

1
2
3
4
5
6
<label htmlFor="insertArea">输入内容</label>
<input
id="insertArea"
value={this.state.inputValue}
onChange={this.handleInputChange.bind(this)}
/>

组件拆分

我们把li标签中的内容注释掉并提取出来封装为一个组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import ToDoItem from "./ToDoItem";
<ul>
{
this.state.list.map((item, index) => {
return (
<Fragment>
<ToDoItem/>
{
/*<li
key={index}
onClick={this.handleDelete.bind(this, index)}
>{item}</li>*/
}
</Fragment>
);
})
}
</ul>

1
2
3
4
5
6
7
8
import React, {Component, Fragment} from 'react'

class ToDoItem extends Component{
render() {
return <li>item</li>
}
}
export default ToDoItem

此时点击提交按钮每次新增的都是一个固定的item值,这也不是我们想要的

组件动态传值

我们可以利用组件传值解决上面的问题,代码做如下修改
传递数据:

1
2
3
4
<ToDoItem
content={item}
index={index}
/>

在ToDoItem中接收:

1
return <li>{this.props.content}</li>

传递方法:

1
2
3
4
5
6
<ToDoItem
content={item}
index={index}
//把todolist这个组件的this对象强制传递给todoitem,这样在todoitem中才能调用todolist的handleDelete方法成功
deleteItem={this.handleDelete.bind(this)}
/>

在ToDoItem中接收:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ToDoItem extends Component{
constructor(props) {
super(props);
//通过bind去修改this指向,保证在handleClick可以使用this.props,并且在组件创建的时候
//通过第一个执行的方法constructor去改变handleClick的this指向
this.handleClick = this.handleClick.bind(this);
}
render() {
return <li
onClick={this.handleClick}
>{this.props.content}</li>
}

handleClick() {
this.props.deleteItem(this.props.index)
}
}

单向数据流:
子组件不能修改父组件传递的数据值,如果要修改只能通过父组件向子组件传递方法来修改

代码优化

TodoList

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
class TodoList extends Component{
constructor(props) {
super(props);
this.state = {
inputValue: "",
list: [],
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleButtonClick = this.handleButtonClick.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
render() {
return (
<Fragment>
<div>
<label htmlFor="insertArea">输入内容</label>
<input
id="insertArea"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
<button onClick={this.handleButtonClick}>提交</button>
</div>
<ul>
{this.getToDoItem()}
</ul>
</Fragment>
)
}
handleInputChange(e) {
const value = e.target.value;
this.setState(() => ({
inputValue: value,
}));
}
handleButtonClick(index) {
this.setState((prevState) => ({
list: [...prevState.list, prevState.inputValue],
inputValue: "",
}));
}
handleDelete (index) {
this.setState((prevState) => {
const list = [...this.state.list];
list.splice(index, 1);
return {list} //等价于{list: list}
});
}
getToDoItem () {
return this.state.list.map((item, index) => {
return (
<ToDoItem key={index}
content={item}
index={index}
deleteItem={this.handleDelete}
/>
);
})
}
}

TodoItem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ToDoItem extends Component{
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
const { content } = this.props;
return <li
onClick={this.handleClick}
>{content}</li>
}

handleClick() {
const {deleteItem, index} = this.props;
deleteItem(index)
}
}

总结:

react特点:

  • 声明式开发:减少DOM操作
  • 可以与其它框架并存:flex,redux框架来解决复杂组件通信
  • 组件化
  • 单向数据流
  • 视图层框架:在嵌套包含多个组件的项目中只做视图渲染开发
  • 函数式编程:方便自动化测试
-------------本文结束感谢您的阅读-------------