React基础

记录一下React基础相关的知识点。

ES6

Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
test = async () => {
// return 'xxx' // in then
// in then, add async necessary
// return new Error('error!')

// in catch, add async necessary
// throw new Error('error!')

// in then, add async unnecessary
// return Promise.resolve('xxx')

// in catch, add async unnecessary
// return Promise.reject(new Error('error!'))

// add async unnecessary
/* return new Promise((resolve, reject) => {
// in then
// resolve('yyy')
// in catch
// throw new Error('error!')
// in catch
reject(new Error('error!'))
}) */
}

async

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
async fetch() {
this.props.loadList()
this.fetchPerson('Billy')
// .then(this.fetchOrders)
.then(person => this.fetchOrders(person))
.then(orders => {
orders.forEach(order => {
console.log(order)
})
})
.catch(console.error)
// let person = await this.fetchPerson('Billy')
// let orders = await this.fetchOrders(person)
// orders.forEach(order => {
// console.log(order)
// })
}

// call
this.test().then(
x => {
alert('x->' + x)
}/* ,
err => {
alert('e->' + err)
} */
// catch与then中的第二个参数效果一样
).catch(err => {
alert('e->' + err)
})
)

async fetchOrders(person) {
const orders = person.orderIds.map(id => ({ id }))
return orders
}

async fetchPerson(name) {
return {
name,
orderIds: ['A', 'B']
}
}

React生命周期

react-lifecycle.jpeg

初始化(无子组件):

1
constructor->componentWillMount->render->componentDidMount

初始化(有子组件):

1
2
3
父组件:constructor->componentWillMount->render
子组件:->constructor->componentWillMount->render->componentDidMount
父组件:->componentDidMount

state改变时(无子组件):

1
shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate

state改变时(有子组件):

1
2
3
父组件:shouldComponentUpdate->componentWillUpdate->render
子组件:->componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
父组件:->componentDidUpdate

离开页面时:

1
componentWillUnmount

如果父组件的state改变时,所有子组件或者子组件在render()中的prop值都会改变:

1
子组件render()方法:<MyTextArea defaultValue={this.props.test} />

如果将子组件的props值定义为state的话,则需要在componentWillReceiveProps设置state:

1
2
3
4
5
6
7
8
9
10
11
12
constructor(props) {
super(props)
this.state = {
test: props.test
}
}
componentWillReceiveProps = nextProps => {
this.setState({
test: nextProps.test
})
}
子组件render()方法:<MyTextArea defaultValue={this.state.test} />

如何避免这些不必要的render:

使用shouldComponentUpdate()以让React知道当前状态或属性的改变是否不影响组件的输出,默认返回ture,返回false时不会重写render,而且该方法并不会在初始化渲染或当使用forceUpdate()时被调用,我们要做的只是这样:

1
2
3
shouldComponentUpdate(nextProps, nextState) {
return nextState.someData !== this.state.someData
}

react路由

Switch

1
2
3
4
5
<Switch>
<Route path="/demo/list" component={List} exact />
<Route path="/demo/detail/:id" component={Detail} />
<Redirect to="/demo/list" />
</Switch>

Switch表示有多少Route时,只加载找到的第一条Route。 exact表示精确匹配。没有加exact模糊匹配。

子组件配置路由

1
2
3
4
5
6
pages/home/index.js(第一次会加载这个页面):
<Switch>
<Route path="/" component={MainPage} exact />
<Route path="/demo" component={Demo} />
<Route path="*" component={NotFoundPage} />
</Switch>

注意:不能加exact,否则子组件中的路由无法加载。

1
2
3
4
5
6
/demo/index.js:
<Switch>
<Route path="/demo/list" component={List} />
<Route path="/demo/detail/:id" component={Detail} />
<Redirect to="/demo/list" />
</Switch>

react-route必须要在系统第一次加载路由。通过点击进来的页面如果配置的路由在第一次没有加载,就报错。/demo在第一次就载了,所以子组件配置/demo开头的路由可以。但如果子组的路由不是以/demo的就有问题。估计是react router的限制。

/demo必须要先定义在router.js中,各个组件中可以定义自己的路由,不过前提必须要是/demo开头才行。

所以home下的Index.js中的这行不能加exact,否则路由就加载不了。

/demo/list模糊匹配到了/demo,然后/demo中配置了子组件的路由,就能够成功加载。

参考