无状态和相连组件示例应用程序通过注册一个回调来订阅 Redux 存储,只要存储状态发生更改,Redux 就会调用该回调。该回调呈现整个应用程序。实际上,用户会将整个应用程序连接到 Redux 存储。对于演示用途,连接整个应用程序已足够了,但最好通过 React 的 forceUpdate() 函数将 Redux 存储连接到单个组件。
清单 8 给出了交通信号灯应用程序的一个改良的入口点。
清单 8. 交通信号灯应用程序的改良后的入口点 (index.js)1
2
3
4
5
6
7
8
9
10
11
| 'use strict';
import React from 'react';
import ReactDOM from 'react-dom';
import Redux, { createStore } from 'redux';
import { reducer } from './reducer';
import { App } from './app';
ReactDOM.render(<App store={createStore(reducer)}/>,
document.getElementById('root'))
|
将清单 8 与 比较,可以看到代码不再在应用程序级别上订阅 Redux 存储。
清单 9 是一个实现 componentWillMount() 的经过改良的 Stoplight 组件。该方法会订阅 Redux 存储,在存储发生更改时调用该组件的 forceUpdate() 方法。
清单 9. 改良后的 stoplight (stoplight.js)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
| 'use strict';
import React, { Component } from 'react';
const stopColor = (store) => {
return store.getState() == 'STOP' ? 'red' : 'white';
}
const cautionColor = (store) => {
return store.getState() == 'CAUTION' ? 'yellow' : 'white';
}
const goColor = (store) => {
return store.getState() == 'GO' ? 'rgb(39,232,51)' : 'white';
}
export class Stoplight extends Component {
componentWillMount() {
this.props.store.subscribe(() => {
this.forceUpdate();
});
}
render() {
return(
<div style={{textAlign: 'center'}}>
<svg height='170'>
<circle cx='145' cy='60' r='15'
fill={stopColor(this.props.store)}
stroke='black'/>
<circle cx='145' cy='100' r='15'
fill={cautionColor(this.props.store)}
stroke='black'/>
<circle cx='145' cy='140' r='15'
fill={goColor(this.props.store)}
stroke='black'/>
</svg>
</div>
)
}
}
|
清单 10 给出了一个改良后的 Buttons 组件,它经过了类似的改良,实现 componentWillMount() 来订阅 Redux 存储。
清单 10. 改良后的按钮 (buttons.js)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
| 'use strict';
import React, { Component } from 'react';
import { goAction, cautionAction, stopAction } from './actions';
export class Buttons extends Component {
componentWillMount() {
this.props.store.subscribe(() => {
this.forceUpdate();
});
}
render() {
const state = this.props.store.getState();
return(
<div style={{textAlign: 'center'}}>
<button onClick={() => {this.props.store.dispatch(goAction)}}
disabled={state == 'GO' || state == 'CAUTION'}
style={{cursor: 'pointer'}}>
Go
</button>
<button onClick={() => {this.props.store.dispatch(cautionAction)}}
disabled={state == 'CAUTION' || state == 'STOP'}
style={{cursor: 'pointer'}}>
Caution
</button>
<button onClick={() => {this.props.store.dispatch(stopAction)}}
disabled={state == 'STOP' || state == 'GO'}
style={{cursor: 'pointer'}}>
Stop
</button>
</div>
)
}
}
|
将 中的 Stoplight 组件和 中的 Buttons 组件的实现与它们的原始实现比较一下( 和 )。可以看到,除了添加了 componentWillMount() 方法之外,两个组件都从无状态功能组件更改成了类。这是因为 React 无状态功能组件不支持 React 生命周期方法。
其他所有方面均类似,无状态组件最适合维护状态的组件,这也是 Redux 很有用的原因:维护状态容易出错,这是大部分 bug 的源头。在下一期文章中,将学习如何通过使用 Redux React 绑定,将 Stoplight 和 Buttons 组件恢复为无状态组件。 |