# 1.React 创建组件的方式
# 通过 JS 函数 创建(无状态组件,函数式组件)
// 函数创建组件 无状态组件 props
function Clock(props) {
return (
<div>
<h1>现在是 {props.date.toLocaleTimeString()}.</h1>
</div>
);
}
ReactDOM.render(<Clock date={new Date()} />, document.getElementById("app"));
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 特点:
- 无状态组件创建形式使代码的可读性更好,并减少了冗余代码
- 组件不会被实例化,整体渲染性能得到提升
- 组件不能访问 this 对象
- 组件无法访问生命周期的方法(当然如果在使用无状态组件时发现需要用到生命周期时可以使用高阶组件)
- 无状态组件只能访问输入的 props,同样的 props 会得到同样的渲染结果,不会有副作用
# 通过 Class 创建(有状态组件,类组件)
// class创建组件 有状态组件 继承React.Component this.props
class ES6Component extends React.Component {
constructor(props) {
super(props);
// 设置 initial state
this.state = {
text: props.initialValue || "placeholder"
};
// ES6 类中函数必须手动绑定
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</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
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
# 如何选择哪种方式创建组件?
- 优先使用函数组件:适用于大多数场景,尤其是新项目。
- Class 组件的剩余用途:
- 错误边界(componentDidCatch)。
- 需要 getSnapshotBeforeUpdate。
- 依赖组件实例的第三方库集成。
- 迁移策略:逐步替换 Class 组件,利用 Hooks 简化逻辑。
# 2.条件渲染
# &&运算符
render() {
return (
{this.state.alertStatus && <div>1111</div>}
)
}
1
2
3
4
5
2
3
4
5
# 三元运算符
render() {
return (
{this.state.alertStatus ? <div>2222</div> : ''}
)
}
1
2
3
4
5
2
3
4
5
# 3.在哪个生命周期发起Ajax请求
- 放在
componentDidMount
阶段获取 - 该生命周期在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载
# 4.React的生命周期
- 生命周期可分成四个状态
Initialization:初始化阶段。 constructor里面完成props和state的初始化
Mounting:挂载阶段。
Updation:更新阶段。
Unmounting:销毁阶段
# 5.最外层可以不包裹 div 标签,通过 Fragment
import React, { Component, Fragment } from "react";
class Test extends Component {
render() {
return (
<Fragment>
<button>按钮</button>
</Fragment>
);
}
}
export default Test;
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 6.Props(属性)和 State (状态)
React组件的prop
属性为外部传入属性,不可修改
state
为自身状态,用户交互通过改变状态实现重新渲染
# 6.1 React 中 禁止直接操作 state
// 应该通过this.setState 方法
this.setState({
inputValue: e.target.value
})
1
2
3
4
2
3
4
// 在调用完setState之后,如果想拿到最新的state的值,可以会回调函数中拿
this.setState({
},function() { // 回调函数
})
1
2
3
4
5
6
2
3
4
5
6
# 6.2 state(状态)更新可能是异步的
React 为了优化性能,有可能会将多个 setState() 调用合并为一次更新。
因为 this.props 和 this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)
// 错误
this.setState({
counter: this.state.counter + this.props.increment,
})
1
2
3
4
2
3
4
要弥补这个问题,使用另一种 setState() 的形式,它接受一个函数而不是一个对象。
这个函数将接收前一个状态作为第一个参数,应用更新时的 props 作为第二个参数
// 正确
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}))
1
2
3
4
2
3
4
# 7.setState 不一定立即更新
setState 不是异步,而是有一个时间片的概念,在同一个时间片中是不会立即更新到fiber
constructor(props) {
super(props);
this.state = {
isFiltered: false
};
}
toggleFilter = () => {
this.setState({
isFiltered: !this.state.isFiltered
});
this.filterData();
};
filterData = () => {
// this.state.isFiltered 应该是 true,但事实并非如此,因为 setState 可能还没更新
// isFiltered还没有改变
if (this.state.isFiltered) { // Do some filtering }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
解决上述问题正确的做法之一 :使用 setState 回调函数
// 在调用完setState之后,如果想拿到最新的state的值,可以会回调函数中拿
this.setState({
},() => { // 回调函数
})
1
2
3
4
5
6
2
3
4
5
6
因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9