Redux&&react-Redux应用(二)

以一个投票的小案例来分析

整个项目是基于create-react-app构建的,其它的文件目录这里就不编写了,只把SRC中需要的内容列举出来

  • 需要安装bootstrap@3.3.7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|-src
|-component //=>存放项目中的一个个组件
|-VoteButton
|-VoteResult
|-store //=>存储的是REDUX全套管理内容
|-action
|-index.js
|-vote.js
|-reducer
|-index.js
|-vote.js
|-action-types.js
|-index.js
|-index.js //=>项目的主入口,在这里实现JSX元素的渲染

1)定义所有的行为标识

action-types.js

1
2
3
4
5
/*
* 宏观管理当前项目中需要用到的所有行为标识(REDUX中需要使用)
*/
export const VOTE_A = 'VOTE_A';
export const VOTE_B = 'VOTE_B';

2)处理REDUCER

所有容器中的状态修改,都要经过REDUCER统一管理和处理

reducer/vote.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import * as Types from '../action-types';

function vote(state = {
A: 0,
B: 0
}, action) {
state = {...state};
switch (action.type) {
case Types.VOTE_A:
state.A = state.A + 1;
break;
case Types.VOTE_B:
state.B = state.B + 1;
break;
}
return state;
}

export default vote;

reducer/index.js

1
2
3
4
5
6
7
8
/*==合并所有编写的REDUCER==*/
import {combineReducers} from 'redux';
import vote from './vote';

const reducer = combineReducers({
vote: vote
});
export default reducer;

3)编写STORE中的INDEX创建容器

store/index.js

1
2
3
4
5
6
7
8
9
10
11
/*
* 创建容器并且将其导出
* 1、依赖REDUCER
* 2、在这里配置各种中间件
* ...
*/
import {createStore} from 'redux';
import reducer from './reducers/index';

const store = createStore(reducer);
export default store;

4)ACTION-CREATEOR

  • 把后期组件中需要进行DISPATCH派发的任务都封装为具体的方法,返回派发是需要的ACTION对象即可

action/vote.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import * as Types from '../action-types';

const vote = {
supportA() {
return {
type: Types.VOTE_A
}
},
supportB() {
return {
type: Types.VOTE_B
}
}
};
export default vote;

action/index.js

1
2
3
4
5
6
import vote from './vote';

const action = {
vote: vote
};
export default action;

4、编写组件,基于REACT-REDUX完成状态的使用和修改等

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react';
import ReactDOM from 'react-dom';
import VoteResult from "./component/VoteResult";
import VoteButton from "./component/VoteButton";

import {Provider} from 'react-redux';
import store from './store/index';

//=>重要事情:
//1、导入STORE(创建好的容器)
//2、利用REACT-REDUX中的Provider组件(把组件作为根组件),把创建的容器通过属性的方式传递给这个根组件(目的:基于REACT-REDUX的处理,可以把STORE中的状态信息以及DISPATCH传递给当前项目中的每一个子组件 [前提是子组件需要经过高阶处理])
ReactDOM.render(<Provider store={store}>
<div className='panel panel-default'
style={{
width: '50%',
margin: '20px auto'
}}>
<VoteResult/>
<VoteButton/>
</div>
</Provider>, window.root);

component/VoteButton.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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import action from '../store/action/index';

class VoteButton extends React.Component {
constructor(props) {
super(props);
}

render() {
let {supportA, supportB} = this.props;

return <main className='panel-body'>
<button type="button"
className="btn btn-danger"
onClick={supportA}>
赞成
</button>
&nbsp;&nbsp;&nbsp;&nbsp;
<button type="button"
className="btn btn-success"
onClick={supportB}>
反对
</button>
</main>;
}
}

/*const mapStateToProps = state => {
//=>state:存储的是STORE中的状态
//{vote:{A:,B:}}
return {
...state.vote
}//=>返回的是啥,就相当于把这些属性挂载到组件的PROPS上了
};*/

/*const mapDispatchToProps = dispatch => {
const {supportA, supportB} = action.vote;
return {
SA() {
dispatch(supportA());
},
SB() {
dispatch(supportB());
}
}//=>把返回对象中的每一个属性方法挂载到PROPS上
};*/

export default connect(state => ({...state.vote}), action.vote)(VoteButton);

/*
* connect:REACT-REDUX中提供的高阶组件,目的是为了把STORE容器中的STATE/ACTION分别作为组件的属性传递给组件
* 第二个括号中的参数是我们需要处理的组件
* 第一个括号中的参数:
* mapStateToProps:把STORE容器中的STATE作为组件的属性
* mapDispatchToProps:把STORE容器中的派发操作作为组件的属性
*/

component/VoteResult.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
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import action from '../store/action/index';

class VoteResult extends React.Component {
constructor(props) {
super(props);
}

render() {
let {A, B} = this.props,
val = ((A / (A + B)) * 100).toFixed(2) + '%';
(A + B) === 0 ? val = '50%' : null;

return <header className='panel-heading'>
<h3 className='panel-title'>
KK好漂亮啊
</h3>
<div className="progress"
style={{
margin: '20px 0',
background: '#5CB85C'
}}>
<div className="progress-bar"
role="progressbar"
aria-valuenow="60"
aria-valuemin="0"
aria-valuemax="100"
style={{
width: val,
background: '#D9534F'
}}>
{val}
</div>
</div>
</header>;
}
}

export default connect(state => ({...state.vote}), action.vote)(VoteResult);

Comment