0%

React-组件基础

模块与组件和模块化组件的理解

模块

  1. 理解:向外提供特定功能的JS程序,一般就是一个JS文件
  2. 为什么: JS代码更多更复杂
  3. 作用:复用JS,简化Js的编写,提高JS的运行效率

组件

  1. 理解: 用来实现特定(局部)功能效果的代码集合(html/js/css)
  2. 为什么:一个界面的功能更复杂
  3. 作用:提高代码的复用性,便于程序可维护性,提高运行效率

模块化

当应用的js都以模块来编写,这个应用就是一个模块化应用

组件化

当应用是以多组件的方式实现,这个应用就是一个组件化应用

React 组件介绍

  • 组件是 React 的一等公民,使用 React 就是在用组件
  • 组件表示页面中的部分功能
  • 组合多个组件实现完整的页面功能
  • 特点:可复用、独立、可组合

React 组件的两种创建方式

1.使用函数创建组件

2.使用类创建组件

使用函数创建组件

  • 函数组件:使用 JS 的函数(或箭头函数)创建的组件
  • 约定1:函数名称必须以大写字母开否
  • 约定2:函数组件必须有返回值,表示该组件的结构
  • 如果返回值为 null,表示不渲染任何内容
  • 使用函数名作为组件标签名
1
2
3
4
5
6
7
8
9
10
11

// 创建函数式组件
function MyComponet() {// 组件名必须大写开头
// 必须有返回值
return (< div> MyComponet 组件 </div>)
}
// 使用箭头函数创建组件
const Hello = () => (<div>Hello 组件<MyComponet /></div>)


ReactDOM.render(<Hello />, document.getElementById('root'));

使用类创建组件

  • 类组件:使用 ES6中 class 关键字创建的组件
  • 约定1:类名称也必须以大写字母开头
  • 约定2:类组件应继承React.Component父类,从而可以使用父类中提供的属性或方法
  • 约定3:类组件必须提供render()方法
  • 约定3:render()方法必须有返回值表示该组件的结构
1
2
3
4
5
6
7
8
9
import './index.css'
// 使用类声明的方式创建组件
class Hello extends React.Component {

render() {
return (<div>我是Class声明的组件Hello</div>)
}
}
ReactDOM.render(<Hello />, document.getElementById('root'));

抽离为独立 JS 文件

  • 思考:项目中的组件多了之后,该如何组织这些组件呢?
  • 选项一:将所有组件放在同一个JS文件中
  • 选项二:将每个组件抽离到独立的JS文件中
  • 组件作为一个独立的个体,一般都会放到独立的JS文件中

步骤:

1.创建Components目录

2.创建Hello.js文件

3.创建组件(函数 或 类)

4.在index.js 中导入Hello 组件

5.渲染组件

1
2
3
4
5
6
7
8
9
10
import React from 'react';

class Hello extends React.Component {

render() {
return (<div>Hello 组件的抽离</div>)
}
}

export default Hello;
1
2
3
4
5
6
7
// 导入 react
import React from 'react';
import ReactDOM, { render } from 'react-dom';
// 引入 组件
import Hello from './Components/Hello'

ReactDOM.render(<Hello />, document.getElementById('root'));

React 事件处理

1.事件绑定

2.事件对象

事件绑定

  • React 事件绑定语法与 DOM 事件语法相似
  • 语法:on+事件名称={事件处理程序},比如:onClick={()=>{}}
  • 注意:React 事件采用驼峰命名法,比如:onMouseEnter、onFocus
  • 在函数组件中绑定事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 导入 react
import React from 'react';
import ReactDOM, { render } from 'react-dom';

class Hello extends React.Component {

handleClick() { //事件处理器
console.log('事件被触发');
}
render() {
return (
<div>
<div>Hello 组件的抽离</div>
<button onClick={this.handleClick}>按钮</button>
</div>

);
}
}

ReactDOM.render(<Hello />, document.getElementById('root'));
1
2
3
4
5
6
7
8
9

// 函数式组件
function MyComponent() {
function handleClick() {
console.log('MyComponent 的事件被触发');
}
return (<button onClick={this.handleClick}>按钮2</button>)
}
ReactDOM.render(<MyComponent />, document.getElementById('root'));

事件对象

  • 可以通过事件处理程序的参数获取事件对象
  • 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
// 导入 react
import React from 'react';
import ReactDOM, {
render
} from 'react-dom';

class Hello extends React.Component {

handleClick(e) { //事件处理器
//阻止默认事件
//preventDefault()[dom标准写法(ie678不兼容)]
//ie678用returnValue
//或者利用return false也能阻止默认行为,没有兼容问题(只限传统注册方式)
e.preventDefault();
console.log('事件对象', e);
}
render() {
return (<div>
<a href='http://www.baidu.com/' onClick={this.handleClick}>按钮</a>
</div>

);
}
}



ReactDOM.render(< Hello />, document.getElementById('root'));

有状态组件和无状态组件

  • 函数组件又叫做无状态组件,类组件又叫做状态组件
  • 状态(state)即数据
  • 函数组件没有自己的状态,只负责数据展示(静)
  • 类组件有自己的状态,负责更新UI,让页面“动”起来

比如计数器案例中,点击按钮让数值加1.0和1就是不同时刻的状态,而由0变为1就表示状态发生了变化,状态变化后。UI也要相应的更新。React 中想要实现该功能,就要使用有状态组件来完成。

状态改变

组件中的state 和 setState()

1.state的基本使用

2.setState()修改状态

state的基本使用

  • state是组件对象最重要的私有属性,值是对象(可以包含多个数据,类似Vue中vm实例的data属性)

  • state 的值是对象,表示一个组件可以有多个数据

  • 获取状态:this.state

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Hello extends React.Component {
constructor() {
super();
// 初始化state
this.state = {
data: 1,
}
}

render() {
return (
<div>
<div>有状态组件</div>
</div>
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Hello extends React.Component {

// ES6 简化语法
state = {
count: 0
}
render() {
return (
<div>
<div>有状态组件{this.state.count}</div>
</div>
);
}
}

setState() 修改状态

  • 状态时可变的
  • 语法:this.setState({要修改的数据})
  • 注意:不要直接修改state中的状态,这是错误的!!
  • setState() 作用:1.修改 state 2.更新 UI
  • 思想:数据驱动试图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Hello extends React.Component {
// ES6 简化语法
state = {
count: 0,
text: 'a'
}
render() {
let state = this.state;
return (
<div>
<h2>计数器:{state.count}</h2>
<button onClick={() => {
this.setState((state) => {
return {
count: state.count + 1
}
})
}}>+1</button>
</div>
);
}
}

从 JSX 中抽离事件处理程序

  • JSX 中参杂了过多 JS逻辑代码,会显得非常混乱
  • 推荐:将逻辑抽离到单独的方法中,包整 JSX结构清晰

错误

  • 原因:事件处理程序中 this 的值为 undefined
  • 希望:this指向组件实例(render方法中的this即为组件实例)

事件绑定 this 指向

1.箭头函数

2.Function.prototype.bind()

3.class 的实例方法

箭头函数

  • 利用箭头函数自身不绑定 this 的特点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

class Hello extends React.Component {

// ES6 简化语法
state = {
count: 0,
text: 'a'
}
onIncrement() {
let state = this.state;
this.setState({ count: state.count + 1 })
}

render() {
let state = this.state;
return (
<div>
<h2>计数器:{state.count}</h2>
<button onClick={()=>{this.onIncrement()}
}>+1</button>
</div>
);
}

bind() 方法

  • 利用ES5中bind()方法,将事件处理程序中的this与组件实例绑定到一起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Hello extends React.Component {

// ES6 简化语法
state = {
count: 0,
text: 'a'
}

// 事件处理程序
onIncrement() {
let state = this.state;
this.setState({ count: state.count + 1 })
}
render() {
let state = this.state;
return (
<div>
<h2>计数器:{state.count}</h2>
<button onClick={this.onIncrement.bind(this)
}>+1</button>
</div>
);
}
}

class 的实例方法

  • 利用箭头函数形式的class 实例方法
  • 注意:该语法是实验性语法,但是,基于 babel 的存在可以直接使用
1
2
3
4
5
onIncrement = () => {

let state = this.state;
this.setState({ count: state.count + 1 })
}

表单处理

1.受控组件

2.非受控组件(DOM方式)

受控组件

  • HTML 中的表单元素是可输入的,也就是有自己的可变状态
  • 而,React 中可变状态通常保存在state中,并且只能通过 setState() 方法来修饰
  • React 将 state 与表单元素的value值绑定到一起,由 state的值来控制表单元素的值
  • 受控组件:其值收到 React 控制的表单元素
受控组件

步骤:

1.在state 中添加一个状态,作为表单元素的value值(控制表单元素值的来源)

2.给表单元素绑定change事件,将 表单元素的值 设置为 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
class Hello extends React.Component {

// ES6 简化语法
state = {
form: {
name: ''
}
}

handelChange = (e) => {
this.setState({
form: {
name: e.target.value
}
})
}
render() {
let state = this.state;
return (
<div>
<input type="text" name="" id="" value={this.state.form.name} onChange={this.handelChange} />
</div>
);
}
}

示例:

1.文本框、富文本标签,下拉框

2.复选框

3.注意:将input标签的value改为defaultValue,因为用value的话,一直改会一直循环的触发onChange

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
// 导入 react
import React from 'react';
import ReactDOM, {
render
} from 'react-dom';

class Hello extends React.Component {

// ES6 简化语法
state = {
form: {
name: '',
content: '',
address: 'bj',
isChecked: false
}
}

// 文本框事件
handelChange = e => {
this.setState({
form: {
name: e.target.value
}
})
}
// 富文本事件
ContentChange = e => {
this.setState({
form: {
content: e.target.value
}
})
}
// 下拉框事件
SelectChange = e => {
this.setState({
form: {
address: e.target.value
}
})
}
handelCheck = e => {
this.setState({
form: {
isChecked: e.target.checked
}
})
}
render() {
let state = this.state;
return (
<div>
{/* 文本框 */}
<input type="text" name="" id="" defaultValue={state.form.name} onChange={this.handelChange} />
<br />
{/* 富文本框 */}
<textarea defaultValue={state.form.content} onChange={this.ContentChange} ></textarea>
<br />
{/* 下拉框 */}
<select defaultValue={state.form.address} onChange={this.SelectChange}>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="gz">广州</option>
</select>
{/* 复选框 */}
<input type="checkbox" checked={state.form.isChecked} onChange={this.handelCheck} />
</div>
);
}
}

ReactDOM.render(< Hello />, document.getElementById('root'));

多表单元素优化:

  • 问题:每个表单元素都有一个单独的事件处理太繁琐
  • 优化:使用一个事件处理程序同时处理多个表单元素

多表单元素优化步骤

1.给表单添加name属性,名称与state 相同

2.根据表单元素类型获取对应值

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
import React from 'react';
import ReactDOM, {
render
} from 'react-dom';

class Hello extends React.Component {

// ES6 简化语法
state = {
form: {
name: '',
content: '',
address: 'bj',
isChecked: false
}
}

// 多表单元素事件整合
handelChange = e => {
// 获取当前DOM对象
const { target } = e;

// 获取类型取值
const value = target.type === 'checkbox' ? target.checked : target.value;

// 设置值
this.setState({
[target.name]: value
})
}

render() {
let state = this.state;
return (
<div>
{/* 文本框 */}
<input type="text" name="name" id="" defaultValue={state.form.name} onChange={this.handelChange} />
<br />
{/* 富文本框 */}
<textarea defaultValue={state.form.content} name='content' onChange={this.handelChange} ></textarea>
<br />
{/* 下拉框 */}
<select defaultValue={state.form.address} name='address' onChange={this.handelChange}>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="gz">广州</option>
</select>
{/* 复选框 */}
<input type="checkbox" checked={state.form.isChecked} name='isChecked' onChange={this.handelChange} />
</div>
);
}
}

ReactDOM.render(< Hello />, document.getElementById('root'));

非受控组件

  • 说明:借助于ref,使原生 DOM 方式来获取表单元素值
  • ref 的作用:获取 DOM 或组件

使用步骤:

1.使用React.createRef()方法创建一个 ref 对象

1
2
3
4
constructor(){
super();
this.txtRef = React.createRef()
}

2.将创建好的ref对象添加到文本中

1
<input type="text" ref={this.textRef} />

3.通过ref对象获取文本框的值

1
Console.log(this.textRef.current.value)

总结

1.组件两种创建方式:函数组件和类组件

2.无状态(函数)组件,负责静态结构展示

3.有状态(类)组件,负责更新UI,让页面动起来

4.绑定事件注意 this 指向问题

5.推荐使用受控组件来处理表单

谢谢老板