以一个投票的小案例来分析
整个项目是基于create-react-app构建的,其它的文件目录这里就不编写了,只把SRC中需要的内容列举出来
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
|
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
| 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
|
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';
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> <button type="button" className="btn btn-success" onClick={supportB}> 反对 </button> </main>; } }
export default connect(state => ({...state.vote}), action.vote)(VoteButton);
|
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