[一步一步學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')
);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章