[一步一步学react系列] 04—计算器Demo

前言:
之前的例子都是写的计数器,加一减一的功能,我们大致弄懂了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数据划分遵循三原则
1. 是否是通过父级props传来的,如果是则可能不是state
2. 会随时间推移而不变吗? 如果是则可能不是state
3. 你能根据组件中其他任何的state或者props计算出他吗?如果能,则可能不是state

由上推理:

  • 等号及等号前的数据: 通过用户的输入而来 会随时间推移而变 state
  • 等号后的数据: 能够计算得出
  • 按钮的值: 来源于父级props层层传递而来

综上我们可以得到属于本组件state状态的数据是:等号及等号前的数据
而每次计算的结果我们则存到redux的store里。即结果来源于props。
关于结果:
我们对应一个方法和一个参数

  • 方法:等于符号的点击 equalClick => 负责向外分发action
  • 参数: revdata 结果值 =>继承自strore,this.props.revdata

难点解说: http://www.xiexianbo.xin/wordpress/?p=519

源码解读:

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 + ' =' ; 
                //向外分发action
                this.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触发reducer
        equalClick: (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.js
import 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')
);

猜你喜欢

转载自blog.csdn.net/young_Emily/article/details/79021954