一個被寫爛的redux計數小例子

東東東東東丶發表於2018-11-28

簡單準備

  • 通過create-react-app快速搭建react專案
  • 安裝依賴npm install redux react-redux redux-thunk --save (redux-thunk是處理非同步資料流的中介軟體)
  • 更改,新建專案目錄

一個被寫爛的redux計數小例子

  • 效果圖
    一個被寫爛的redux計數小例子

Demo開始

編寫redux相關內容

action

export const Increment = 'increment'
export const Decrement = 'decrement'
/*action creator action建構函式*/
export const increment = (counterIndex) => {
  type:Increment,
  counterIndex
}
export const decrement = (counterIndex) => ({
  type: Decrement,
  counterIndex
})
複製程式碼

Action 本質上是 JavaScript 普通物件。action 內必須使用一個字串型別的 type 欄位來表示將要執行的動作,但是這樣有多少action就需要寫多少action,所以這裡需要action creator, 這個action建構函式返回一個js物件,當然這裡在處理非同步資料的時候需要返回一個函式,此時需要用到中介軟體去改寫dispatch。

reducer

import { Increment, Decrement } from '../Action'
export default (state,action) => {
  const {counterIndex} = action
  switch (action.type) {
    case Increment:
    return {...state, [counterIndex]:state[counterIndex]+1}
    case Decrement:
    return {...state, [counterIndex]:state[counterIndex]-1}
    default:
    return state
  }
}
複製程式碼

reducer具體定義可以看redux自述中的定義,由於demo太簡單,拆分合並reducer大家自己看吧,這裡主要介紹redux在react中的工作流程。 這裡要注意reducer是個純函式,不能更改state,這裡返回的新state可以使用Object.assign 以及 es6的物件擴充套件符。

store

import {applyMiddleware, createStore} from 'redux'
import thunk from 'redux-thunk'
import reducer from '../Reducer'
const initValue={
    'First':1,
    'Second':5,
    'Third':6
}
const store=createStore(reducer,initValue)
export default store
複製程式碼

createStorestore 可以接受一個初始的state,這裡可以設定服務端同構應用的初始化props。 至此redux的相關就結束,下面寫ui元件。

編寫UI元件

如果不用react-redux自動生成容器元件,元件劃分就要有容器元件和展示的區分,我理解的展示元件就是沒有自己的state,只接受 props決定UI該如何展示,所有的邏輯都在容器元件進行,由於react-redux,我們不需要自己寫容器元件

Counter

    import React, { Component } from 'react';
    import {increment, decrement} from '../Redux/Action'
    import {connect} from 'react-redux'
    import '../style/App.css';
    const buttonMargin= {
      margin: "20px"
    }
    
    function Counter({index, Increment, Decrement, value}){
      return (
                <div>
                   <button style={buttonMargin} onClick={Increment}>+</button>
                   <button style={buttonMargin} onClick={Decrement}>-</button>
                   <span>{index} count :{value}</span>
                </div>
      )
    }
    function mapStateToProps(state,ownProps){
      return{
        value:state[ownProps.index]
      }
    }
    function mapDispatchToProps(dispatch, ownProps){
      return{
        Increment:() => {
          dispatch(increment(ownProps.index))
        },
        Decrement:() => {
          dispatch(decrement(ownProps.index))
        }
      }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Counter);
複製程式碼
  • react-redux提供方法connect()和元件,這裡說下connect(),引用阮一峰大神的總結: connect方法接受兩個引數:mapStateToProps和mapDispatchToProps。它們定義了 UI 元件的業務邏輯。前者負責輸入邏輯,即將state對映到 UI 元件的引數(props),後者負責輸出邏輯,即將使用者對 UI 元件的操作對映成 Action。
  • mapStateToProps:作為函式,mapStateToProps執行後應該返回一個物件,裡面的每一個鍵值對就是一個對映。 接受兩個引數state,ownProps,state 。state更新的時候,就會自動執行,重新計算 UI 元件的引數,從而觸發 UI 元件的重新渲染,ownProps代表容器元件的props物件,如果容器元件的引數發生變化,也會引發 UI 元件重新渲染,例如上面個的計數;
  • mapDispatchToProps是connect函式的第二個引數,用來建立 UI 元件的引數到store.dispatch方法的對映。也就是說,它定義了哪些使用者的操作應該當作 Action,傳給 Store。它可以是一個函式,也可以是一個物件

Panel

import React, { Component } from 'react'
import Counter from './Counter.js'
const style = {
    margin: "20px"
}

class Panel extends Component {
    render() {
        return (
            <div style={style}>
                <Counter index="First" />
                <Counter index="Second"/>
                <Counter index="Third" />
                <hr/>
            </div>
        )
    }
}
複製程式碼

export default Panel

這裡就是個list。

index.js(入口檔案)

import React from 'react';
import ReactDOM from 'react-dom';
import './style/index.css';
import Panel from './Component/Panel';
import {Provider} from 'react-redux';
import store from './Redux/Store/store.js'
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(
       <Provider store={store}>
         <Panel/>
       </Provider>,<pre>
   document.getElementById('root')
  );
registerServiceWorker();
複製程式碼

React-Redux 提供Provider元件,可以讓容器元件拿到state,避免一層層向下傳,原理是context,其實也很好理解,vue有個bus。 至此一個同步的redux處理資料的demo就完成了,下面來說非同步。

非同步

vuex 提交的是Mutation(有點像git) 這個東西是同步, 而它有action 這裡可以同步非同步,但redux並沒有,所以這裡就有了中介軟體的出現,用於解決非同步action,中介軟體有幾種常用的,這裡只簡單寫下redux-thunk。 action creator 原則是返回一個js物件,非同步在這裡處理,返回的是一個函式,這就需要中介軟體的處理。 修改這兩處:

action:

export const Increment = 'increment'
export const Decrement = 'decrement'

export const increment = (counterIndex) => {
   return dispatch => {
		let asyncAct = {
			type:Increment,
                        counterIndex
		}
		setTimeout(()=>{ //兩秒鐘之後再傳送action
			dispatch(asyncAct);
		}, 2000)
	}
 }
export const decrement = (counterIndex) => ({
   type: Decrement,
   counterIndex
 })
複製程式碼

store:

import {applyMiddleware, createStore} from 'redux'
import thunk from 'redux-thunk'
import reducer from '../Reducer'
const initValue={
    'First':1,
    'Second':5,
    'Third':6
}
const store=createStore(reducer,initValue,applyMiddleware(thunk))
//使用中介軟體的寫法applyMiddleware,如果多個,注意裡面中介軟體的順序
export default store
複製程式碼

簡單的延時2s再計數完成啦。

相關文章