老博文迁移,原地址
前言
之前的例子都是写的计数器,加一减一的功能,我们大致弄懂了redux分层和store数据管理,下面我们将结合现有知识写一个终极版的计算器。以此巩固所学知识 知识点:redux分层,react-router,一些算法及数据结构知识[栈 + 中缀转后缀]
首段祭出源码地址:
github:https://github.com/EmilyYoung71415/LearnReactDemo
效果图

项目结构
├──redux-demo/ * 计算器Demo||————src/ * 主程序│├─Components * 所有组件│ ├─Calculator * 计算器│ ├─Counter * 计数器│ └─StudyDemos * 学习的一些有帮助的demo│ └─备份文件夹 * 笔记 等我写完博客就清├─Error * 错误组件├─Redux * Redux│ ├─Action│ ├─Containers│ ├─Reducer│ └─Store├─Router * 路由└─Style * 所有样式变量
为了便于初学者如我上手,我没有将分层的各个功能部件写在不同的文件下,而是采用了先写在一起然后分成多个文件的策略。如下是我的计算器代码,并没有加路由。
思路是:
1.布局:按钮值是数组,循环数组值生成按钮,一个函数监听所有的点击事件。flex布局,固定每行几个块。
2.确定当前实例中拥有的所有数据,接下来在这些数据中找出应该是state的数据。
即:在当前实例[计算器]中的所有数据,确定哪些是本组件内部管理的无需存到store上的数据。
也就是确定props数据与state数据。
props数据与state数据划分遵循三原则:
- 是否是通过父级props传来的,如果是则可能不是state
- 会随时间推移而不变吗? 如果是则可能不是state
- 你能根据组件中其他任何的state或者props计算出他吗?如果能,则可能不是state
由上推理:
- 等号及等号前的数据: 通过用户的输入而来 会随时间推移而变 state
- 等号后的数据: 能够计算得出
- 按钮的值: 来源于父级props层层传递而来
综上我们可以得到属于本组件state状态的数据是:等号及等号前的数据
而每次计算的结果我们则存到redux的store里。即结果来源于props。
关于结果:
我们对应一个方法和一个参数
- 方法:等于符号的点击 equalClick => 负责向外分发action
- 参数: revdata 结果值 =>继承自strore,this.props.revdata
源码解读
import React, {Component} from 'react';import { createStore } from 'redux'import { connect } from 'react-redux'import suffixExpression from './stack'import '../../Style/calcuator.css'const KEYVALUE = [{value: '7'},{value: '8'},{value: '9'},{value: '←'},{value: 'C'},{value: '4'},{value: '5'},{value: '6'},{value: '*'},{value: '/'},{value: '1'},{value: '2'},{value: '3'},{value: '+'},{value: '-'},{value: '0'},{value: '00'},{value: '.'},{value: '%'},{value: '='},{value: '('},{value: ')'}];class MyCalculator extends Component {constructor(props){super(props);this.state = {valueText: '0' //实时更新用户输入的值}}handleValueInput(data) {let oldState = this.state.valueText;//传入当前文本框的值和当前按钮按下的值,调用checkClickType依据不同的按钮值做不同的反应,返回新的值。let rev = this.checkClickType(oldState,data);let newState = {};newState.valueText = rev;this.setState( newState)}checkClickType(oldvalue,value){switch (value) {case '=':let resultbefore = oldvalue + ' =' ;//向外分发actionthis.props.equalClick(oldvalue);return resultbefore;case '←'://删除最后一位oldvalue = oldvalue.substring(0,oldvalue.length-1)return oldvalue;case 'C':oldvalue = '0';return oldvalue;case '+':case '-':case '/':case '*':case '(':case ')':return oldvalue + ' ' +value + ' ';//运算符与操作数以空格为分割default://一般数字if(oldvalue === '0'){//清零oldvalue = ''}return oldvalue + value}}render() {const {revdata} = this.props;//获得最新的结果值let buttonlist = [];KEYVALUE.forEach(data => {buttonlist.push(<button className='div_class_button'key={data.value}onClick = {this.handleValueInput.bind(this,data.value)}>{data.value}</button>);});//取当前input框字符串的最后一个字符 如果是等于符号则 运算过程+结果let str = this.state.valueText;let laststr = str.charAt(str.length - 1)let curValue = str;if(laststr === '='){curValue = str +' '+revdata;}return (<div className='div_class_calculator'><div className='div_class_showdatabar'><h1>简易计算器</h1><input type="text"value={curValue}readOnly/></div><div className='div_class_buttonlist'>{buttonlist}</div></div>);}}/*** @func 模块--container* @desc 定义映射*///将UI组件的props与redux的state映射function mapStateToProps(state) {return {revdata: state.revdata}}//将UI组件的props与redux的action映射function mapDispatchToProps(dispatch) {return {//用户的onIncreaseClick方法与action映射([3]定义action),通过dispatch触发reducerequalClick: (value) => dispatch(getResult(value))}}/*** @func 模块--action* @desc*/const EQUEALBTN = 'EQUEALBTN'; //常规按钮const ActionGenerator = (type, num) => (num) => {let action = { type, num : num }return action}const getResult = ActionGenerator(EQUEALBTN, null);/*** @func 模块--connect*/const App = connect(mapStateToProps,mapDispatchToProps)(MyCalculator)/*** @func 模块--reducer* @desc 根据action 返回新的state*/function getRev(state = { revdata: 0 }, action) {//action.num即是等号前面的字符串switch (action.type) {case EQUEALBTN://let test = '1 + 78 + 22 + ( 10 - 2 ) * 6';let rev = suffixExpression(action.num)//具体的计算处理,我采用的是中缀转后缀计算方法。return { revdata: rev }default:return state}}/*** @func 模块--store* @desc 以reducer生成store对象*/const store = createStore(getRev)export {store,App};
//index.jsimport React from 'react';import ReactDOM from 'react-dom';import { Provider } from 'react-redux'import {store,App} from './Components/Calculator/calculatorAll';ReactDOM.render(<Provider store={store}>{route}</Provider>,document.getElementById('root'));
