首页

React

大概需要 4 分钟读完

虚拟 DOM

React 不直接操作真实 DOM,而是通过渲染虚拟 DOM 到真实页面。因为有优秀的 DIFF 算法能够保证重用 DOM。

JSX 语法

  1. 定义虚拟 DOM 不写引号
  2. 标签中有 JS 加{}
  3. 样式类名不用 class 用 className
  4. 内联样式要 style={ {key:value} }
  5. 只有一个根标签
  6. 标签必须闭合
  7. 标签首字母
    1. 小写则转为 html 标签无论是否存在,例:div、name
    2. 大写则渲染为 react 对应组件,无则报错

JS 的类

1
2
3
4
5
6
7
8
9
10
11
12
class Pet {
constructor(name){
this.name = name;
}
}

class Cat extends Pet {
constructor(name, age){
super(name);
this.age = age;
}
}

super()是调用父类的构造函数,也是将父类的 this 传递给子类,否则子类是用不了 this 对象的。

类定义的方法都是放在原型对象上。这句话引出的例子就是:

1
2
3
4
5
6
7
8
9
10
11
12
class Weather extends React.Component {
constructor(pros){
super(props);//调用父类构造器,传递this对象
this.changeWeather = this.changeWeather.bing(this);
//将原型对象上的changeWeather传递给Weather的实例对象并且绑定了this
}
changeWeather() {
//放在了Weather的原型对象上
//隐藏了'use strict'
console.log(this);
}
}

类中的 this

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
constructor(name) {
this.name = name;
}
study() {
//类中的方法有隐形的'use strict'
console.log(this);
}
}
const p1 = new Person('tom')
p1.study() //this指向Person
const x = p1.study //
x() //等于函数直接调用study(),又因为严格模式所以输出的是undefined

类的简写

首先的知识点就是在 class 里可以随便写赋值语句,但不可以随便写代码

1
2
3
4
5
6
7
8
9
10
11
12
class Weather extends React.Component {
//初始化state
state = {
isHot:false,
wind:'微风'
}
changeWeather = ()=> {
//changeWeather赋值了一个箭头函数
//箭头函数的this会直接在外层找,在这里就是Weather
console.log(this)//Weather
}
}

展开语法

用于展开数组,在官方的情况下不能展开对象,但是可以用{…object}叫做构造字面量对象时使用。

1
2
3
4
5
6
7
8
9
10
11
12
//基本用法-合并
const arr1 = [1,2,3,4]
const arr2 = [3,4,5]
const arr3 = [...arr1, ...arr2] // [1,2,3,4,5]

//对象的使用场景
const obj1 = {foo:'bar', x:23}
const obj2 = {foo:'bar', x:32}
const obj3 = {...obj1, ...obj2}

//在React中可以展开对象是因为处于babel和react的编译中
ReactDOM.render(<Person {...p}/>, doucument.getElementById('test3'))//仅在这里可用

Props

组件接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。props 是只读的。

首先说一个 PropTypes 规定 prop 的类型

1
2
3
4
5
6
7
8
9
static propTypes = {
name:PropTypes.string.isRequired,
age:PropTypes.number,
speak:PropTypes.func
}
static defaultProps = {
sex:'男',
age:18
}

Ref

下面是几个适合使用 refs 的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//string类型的方式会有“性能不好”的问题
<input ref = "input1"></input>

//最常用
//回调函数的方式在更新过程中会被调用两次,一次null,一次真实DOM对象,但大部分情况无关紧要
<input ref ={ c => this.input1 = c}></input>
//定义成绑定class的绑定函数解决上述问题
saveInput = (c) => this.input1 = c;
<input ref ={this.saveInput}></input>

//最推荐
//React.createRef 调用后生成一个容器,用于储存ref标识的节点
input1 = React.createRef()
......//省略代码
<input ref={this.input1}></input>
//使用的时候是
console.log(this.input1.current.value)

Fragment

用来躲避 JSX 必须要指定一个根标签的情况

1
2
3
4
5
import {Fragment} from 'react'
...
<Fragment key={}>
...
</Fragment>

Context

用来在祖组件后代组件中传递状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const XxxContext = React.createContext()

<XxxContext.Provider value ={数据,可是对象}
子组件
</XxxContext.Provider>

//方式一:仅适用于类组件
static contextType = XxxContext
this.context//可以读取了
//方式二:引入Consumer
<XxxContext.Consumer>
{
value => {value就是返回的数据}
}

PureComponent

Component 中,只要执行 setState(),即使不改变状态,依旧调用 render(),父组件的 render()会触发子组件的 render()。

原因:Component 中的 shouldComponentUpdate()总返回 true。

而 PureComponent 解决了上述问题。

但:

  1. 只进行 props 和 state 的浅比较,如果只是对象内部数据改变,那不会触发 render()
  2. 子组件也要是 PureComponent。

RenderProps

类似 Vue 的 slot,可以在父组件中传一个子组件。

1
2
3
4
<Parent render={(name)=><Son name={name}} />

//父组件中jsx加上
{this.props.render(this.state.name)}

ErrorBoundary

只能用在生产环境,开发环境使用会照样报错.

getDerivedStateFromError 和 componentDidCatch 一般配合使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}

componentDidCatch(error, info) {
//统计页面的错误,发送请求到后台
console.log(error, info);
}

render() {
return (
<div>{hasError ? <h2>当前网络不稳定,稍后再试</h2> : <Child />}</div>
);
}

Hooks

useState

1
2
3
4
// useState返回一个数组,接收一个参数设置为初始值
// 数组第一个为变量名,接受参数为初始值
// 第二个为设置变量的函数
const [count, setCount] = useState(0)
2021年02月25日芝士碎片