类式组件
import {Component} from 'react'
export default class App extends Component{
// constructor 专门用来初始化
constructor(props){
super(props)
// 定义组件内部数据
this.state = {
num:20
}
}
render(){
return (
{/* 在JSX上获取组件内部数据 需要通过 this.state.变量名 */}
<div>{this.state.num}</div>
<button onClick={this.handleClick.bind(this)}>按钮</button>
)
}
handleClick(){
// 需要修改到组件内部数据,需要用到this.setState方法来修改
// 在函数中,如果需要使用this,就得在调用的时候传递this
// this.setState() 这个方法是异步的
// this.setState() 提供的第二个参数是一个回调函数,修改了数据之后才执行
this.setState({
num:this.state.num+1
},()=>{
// 修改数据之后才执行
console.log(this.state.num)
})
}
}
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
super的作用究竟是什么?
super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
super()加与不加props的区别究竟在哪里呢?
这是因为 react 在初始化 class 后,会将 props 自动设置到 this 中,所以在任何地方都可以直接访问 this.props,除了一个地方:
constructor
;所以如果你需要在构造函数内使用this.props,就需要传递props作为super()的参数。
a. 插值语法
import React, { Component } from "react";
export default class App3 extends Component {
state = {
name: "苏东旭",
num: 10,
};
render() {
return (
<div>
<p>{this.state.name}</p>
<p>{this.state.num}</p>
</div>
);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
b. 事件的三种写法
this.事件名.bind(this,传递的参数)
import {Component} from 'react'
export default class App extends Component{
constructor(props){
super(props)
this.state = {
title:"我是标题"
}
this.handleClick = this.handleClick.bind(this)
}
render(){
return (
<>
<button onClick = {this.handleClick.bind(this)}>按钮1</button>
<button onClick = {this.handleClick}>按钮2</button>
<button onClick = {()=>this.handleClick()}>按钮3</button>
</>
)
}
handleClick(){
this.setState({
title:"修改后的标题"
})
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
c. 双向数据绑定
react不会问react双向绑定原理的,没有双向绑定
import React, { Component } from "react";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
val: "默认值",
};
}
inp(e) {
this.setState({
val: e.target.value,
});
}
render() {
return (
<div>
<input
type="text"
value={this.state.val}
onChange={this.inp.bind(this)}
/>
<p>{this.state.val}</p>
</div>
);
}
}
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
d. 循环
react只支持map遍历
import {Component} from 'react'
export default class App extends Component{
constructor(props){
super(props)
this.state = {
arr:['html','css','js','jq','node','ts','vue','react']
}
}
render(){
return (
<>
<ul>
{
this.state.arr.map((item,index)=>{
return (
<li key={index}>{item}</li>
)
})
}
</ul>
</>
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
e. 数组操作
- 普通写法
import React from "react";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
arr: ["html", "css", "js", "jq", "vue"],
};
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)}>添加</button>
<ul>
{this.state.arr.map((item, index) => {
return <li key={item}>{item}</li>;
})}
</ul>
</div>
);
}
handleClick() {
this.setState({
// 浅拷贝
arr: [...this.state.arr, "react"],
});
}
}
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
- 深拷贝写法
import React from "react";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
arr: ["html", "css", "js", "jq", "vue"],
};
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)}>添加</button>
<ul>
{this.state.arr.map((item, index) => {
return <li key={item}>{item}</li>;
})}
</ul>
</div>
);
}
handleClick() {
// 深拷贝
let newArr = JSON.parse(JSON.stringify(this.state.arr));
newArr.push("react");
this.setState({
arr: newArr,
});
}
}
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
f. 父子传值
1. 父传子
在父组件的子组件标签中设置自定义属性,并将要传递的数据作为其属性值
在子组件中直接通过
this.props.自定义属性
获取父组件传递的数据
父组件传值
在父组件中引入子组件
react// 组件名首字母一定大写 import 子组件名 from "子组件位置"
1
2直接用就行,无需注册
render(){ return( <div> <子组件 自定义属性={父组件数据}></子组件> </div> ) }
1
2
3
4
5
6
7
子组件接值
<p>{this.props.自定义属性名}</p>
子组件中限制默认值
jsxstatic defaultProps = { 自定义属性名:"属性值", title:"默认值" }
1
2
3
4子组件中限制类型
jsx// 引入限制类型的模块 import PropTypes from "prop-types" // 限制类型 注意不能直接写类型,需要单独引入 限制类型 的模块 static propTypes = { 自定义属性名:PropTypes.String }
1
2
3
4
5
6
7
2. 子传父
子组件传值
在子组件中为某元素添加点击事件,并将事件触发的方法进行声明,在方法内通过
this.props.自定义事件(传递数据)
在父组件的子组件标签中使用该自定义事件,不加on,自定义事件触发的方法在父组件中进行声明,方法的形参就是子组件传递过来的数据
需要一个契机,为元素添加点击事件
react<button onClick={this.子组件方法.bind(this)}>子组件按钮</button>
1声明点击事件的方法,并通过
this.props.自定义事件(传参)
react子组件方法(v){ this.props.自定义事件("传递的数据") }
1
2
3
父组件接值
子组件标签内,使用自定事件,不加on
react<子组件 自定义事件={this.父组件方法.bind(this)}></子组件>
1父组件中声明子组件自定义事件触发的方法
react父组件方法(v){ //形参v就是子组件传递的数据 }
1
2
3
g. 组件跨级值传递Context
React组件之间的通信是基于props的数据传递,数据需要一级一级从上到下传递。如果组件级别过多传递就会过于麻烦。React中 Context
配置可以解决组件跨级值通信
适合获取数据,如果修改的话,还是建议放在redux中
方式一
向下传递
import React,{Component} from 'react'
import PropTypes from 'prop-types'
// 爷爷
export default class Comp1 extends Component{
// 声明要传递的数据类型
static childContextTypes = {
fnum:PropTypes.number
}
// 保存要传递的数据到上下文环境中
getChildContext(){
return {
fnum:40
}
}
render(){
return (
<Child></Child>
)
}
}
// 爸爸
class Child extends Component {
render(){
return (
<div>
<ChildChild></ChildChild>
</div>
)
}
}
// 孙子
class ChildChild extends Component {
// 在哪个组件中想要获取fnum这个数据,就必须写两个东西
// 1. 接收的类型
static contextTypes = {
fnum:PropTypes.number
}
render(){
return (
<div>
孙子组件
{/* 2. 通过this.context.fnum获取值 */}
{this.context.fnum}
</div>
)
}
}
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
方式二
配置createContext
// ctx.js 哪个组件使用就引入
import {createContext} from "react"
const ctx = createContext()
export default ctx
/*
ctx有两个组件(标签)
Provider 发送数据
Consumer 接收数据
*/
2
3
4
5
6
7
8
9
10
向下传递
父辈通过Provider的value属性向下传递数据
后代通过
(value)=>{}
接收数据
import React, { Component } from "react";
import ctx from "../utils/ctx";
let { Provider, Consumer } = ctx;
// 爷爷
export default class App extends Component {
render() {
return (
<Provider value={{ name: "苏东旭" }}>
<Child></Child>
</Provider>
);
}
}
// 爸爸
class Child extends Component {
render() {
return <ChildChild></ChildChild>;
}
}
// 孙子
class ChildChild extends Component {
render() {
return (
<Consumer>
{(value) => {
return <h2>{value.name}</h2>;
}}
</Consumer>
);
}
}
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 } from "react";
import ctx from "../utils/ctx";
let { Provider, Consumer } = ctx;
// 爷爷
export default class App extends Component {
render() {
return (
<Provider value={{ name: "苏东旭", fn: this.data.bind(this) }}>
<Child></Child>
</Provider>
);
}
data(v) {
console.log(v);
}
}
// 爸爸
class Child extends Component {
render() {
return <ChildChild></ChildChild>;
}
}
// 孙子
class ChildChild extends Component {
render() {
return (
<Consumer>
{(value) => {
return (
<div>
<h2>{value.name}</h2>
<button onClick={value.fn("孙子向上传递的数据")}>传递</button>
</div>
);
}}
</Consumer>
);
}
}
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
h. 组件的生命周期
类的生命周期分为三个大阶段:挂载、更新、卸载
每个大阶段又有若干小阶段,其中在整个生命周期中render会被执行两次(挂载和更新阶段各执行一次)
挂载阶段
constructor
: 当对象刚刚类创建出来的时候
componentWillMount
: 组件即将渲染【没用,现在已经废弃了】
render
: 组件正在渲染
componentDidMount
: 组件渲染完毕
// 当对象刚刚类创建出来的时候
constructor(){
super()
console.log("生命周期的第一个阶段---刚刚创建出来")
//作用:就是为了初始化state的数据
}
// 组件即将渲染【没用,现在已经废弃了】
UNSAFE_componentWillMount(){
console.log("生命周期的第二个阶段---组件即将渲染")
}
// 组件正在渲染
render(){
console.log("生命周期的第三个阶段---组件正在渲染")
}
// 组件渲染完毕
componentDidMount(){
// react官方要求,推荐在componentDidMount中请求数据
console.log("生命周期的第四个阶段---组件渲染完毕")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
更新阶段
shouldComponentUpdate
: 应该更新么,返回true或false
componentWillUpdate
: 即将更新【已废弃】
render
: 正在更新
componentDidUpdate
: 更新完毕
state更新
import React, { Component } from "react";
export default class Child extends Component {
constructor() {
super();
this.state = {
num: 1,
};
}
dian() {
this.setState({
num: "苏东旭",
});
}
// 在这个方法中,判断数据修改前后是否一致,不一致才去render,减少不必要的更新,优化更新性能
shouldComponentUpdate(nextProps, nextState) {
console.log("修改的第一阶段:可以修改么");
if (this.state.num === nextState.num) {
return false;
} else {
return true;
}
}
UNSAFE_componentWillUpdate() {
console.log("修改的第二阶段:即将修改【已废弃】");
}
render() {
console.log("修改的第三阶段:正在修改");
return (
<div>
Child
<p>{this.state.num}</p>
<button onClick={this.dian.bind(this)}>按钮</button>
</div>
);
}
componentDidUpdate() {
console.log("修改的第四阶段:修改完毕");
}
}
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
props改变
componentWillReceiveProps(){
// props数据的变化,才会触发这个方法的执行
}
2
3
卸载阶段
componentWillUnmount
: 主要用于释放数据、清空缓存
componentWillUnmount() {
// 释放数据 清空缓存
console.log("被销毁了");
}
2
3
4
总结:
componentDidMount
适合做数据请求
shouldComponentUpdate
优化更新性能