Redux之旅-1

三月懶驢發表於2016-04-07

時間:2016.4.7-17:24
作者:三月懶驢
入門配置文章:連結

準備

在你的專案下面加入redux / react-redux

    npm install redux --save
    npm install react-redux --save

入門小例子

網上有很多關於Redux的解析了,我也不從抽象化去講解整個redux的作用,而發現講解Redux的程式設計化例子其實很少,所以在這裡用程式碼來說明一下。什麼叫做redux,以及它的Action/reducer/store

看過我上一遍專案環境搭建的朋友應該有一個基本的專案目錄架構。

主要寫程式碼的還是在app這個資料夾裡面,裡面的目錄分佈

   - component -->放置元件的
   - redux     -->放置action && reducer
   - redux_lesson -->目前是放置用Provider打包出來的元件
   - main.js   -->程式入口

程式碼開始前的思考

我們現在要做一個很簡單的東西,用前端的話來說就是一個div標籤,裡面放置一個數字0,當我們點選這個div的時候,裡面的數字就遞增。這裡面我們要進行一步就是,寫程式碼前的思考。
如上所說,我們的需求就是:點選,數字遞增。那麼我們的一些引數應該定義出來了。

改變View的資料—state

個人簡單理解的state就是可以反映到view上的可變資料,這裡我們的state定義如下

state = {count:0}

改變state的鑰匙—Action

同樣是個人理解:state是可變的,但不是隨便的可變,要改變它,就需要一把鑰匙去開啟這道大門,而action就是這把鑰匙了
我們把這個action定義成如下:

increaseAction = {type:`increase`}

Action 本質上是 JavaScript普通物件。我們約定,action內使用一個字串型別的 type欄位來表示將要執行的動作。多數情況下,type 會被定義成字串常量。

改變state的動作—Reducer

個人的胡亂理解:有了state,有了要改變state的鑰匙Action,那麼誰來進行改變state的操作?reducer就是這麼一個加工車間,你拿著原料(state)和鑰匙(Action)進去總車間,用鑰匙(Action)開啟對應的生產線,生產出來新的產品(也是state)回去

let reducer = (state={count:0},action)=>{
    //這裡面傳遞進來兩個引數,
    //一個是我們前面定義的state,如果木有傳入的話,就用{count:0}
    //一個是我們前面定義的action,下面就要檢查它的type來確定操作
    let count = state.count
    switch(action.type){
        //如果鑰匙插對了孔,我們就返回進行了相應操作後的state物件
        case `increase`:
            return {count:count+1}
            break
        //如果鑰匙都不對,就返回沒操作過的state
        default:
            return state
    }
}

被我吃了的store

因為相對前面三個東西來說,store是在太容易理解了,引入官方的話:

Store 就是把它們聯絡到一起的物件。Redux 應用只有一個單一的 store。當需要拆分處理資料的邏輯時,使用 reducer 組合 而不是建立多個 store。

開始真正寫程式碼了

其實上面的步驟我們都把一個redux處理資料的相關工作做的差不多了,那麼接下來就是要真正的去寫成程式

建立action

檔案位置: app/redux/action.js

export const increaseAction = {type:`increase`}

建立reducer

檔案位置: app/redux/reudcer.js

let reducer = (state={count:0},action)=>{
    let count = state.count
    switch(action.type){
        case `increase`:
            return {count:count+1}
            break
        default:
            return state
    }
}
export default reducer

生成store,打包出新元件

重要的事情:store只有一個!

檔案位置: app/redux_lesson/lesson_0.js

`use strict`

import React from `react`
import { createStore } from `redux`
import { Provider,connect } from `react-redux`

//這個index.js檔案會在在下一步建立
import Index from `../component/index`
import reducers from `../redux/reducer`

//建立store
let store = createStore(reducers)
/*
  mapStateToProps你可以理解成在下面connect的時候為元件提供一個props,這個props的值是redux的state
*/
let mapStateToProps = (state) =>{
    return {count:state.count}
}
//連線你的state和最外層的元件
let Content = connect(mapStateToProps)(Index)

let {Component} = React

//使用Provider來把新的App元件打包出來
class App extends Component{
    render(){
        return <Provider store={store}><Content /></Provider>
    }
}

export default App

建立View

在View裡面我們會接受到兩個props。一個是在mapStateToProps生成的state,一個是store給我們的dispatch,這是是一個函式,我們用它的方法很簡單粗暴,往裡面傳入一個Action就行了,它接受了這個Action就會告訴reducer去執行。

檔案位置: app/compoment/index.js

`use strict`

import React from `react`
import { connect } from `react-redux`
//請注意這裡面引入了action
import {increaseAction} from `../redux/action`
let {Component,PropTypes}  = React
class Index extends Component{
    //這一步是檢查傳入的各個prop型別是否正確
    ProTypes = {
        count:PropTypes.number.isRequired,
    }
    constructor(props){
        super(props)
    }
    handleClick(){
        /*
            這一步輸入this.props可以看到,其實裡面有兩個東西
            在下面的render裡面我們用到了this.props.count這個
            那麼這裡我們要用到dispatch
        */
        console.log(this.props)
        let {dispatch} = this.props
        //粗暴簡單的使用
        dispatch(increaseAction)
    }
    render(){
        let {count} = this.props
        return <div onClick = {this.handleClick.bind(this)}  style={styles.circle}>{count}</div>
    }
}
//樣式檔案,不用細看
let styles = {
    circle:{
        width:`100px`,
        height:`100px`,
        position:`absolute`,
        left:`50%`,
        top:`50%`,
        margin:`-50px 0 0 -5px`,
        borderRadius:`50px`,
        fontSize:`60px`,
        color:`#545454`,
        backgroundColor:`#fcfcfc`,
        lineHeight:`100px`,
        textAlign:`center`,
    }
}
export default Index

進一步優化程式碼

要做一個點選遞增就需要那麼多步驟是不是很煩惱?但是如果專案大起來之後,你想像這樣,你就可以建立不同的鑰匙Action,再編寫不同的生產線reducer來修改各自的state,但是如上所做,我們的邏輯程式碼(點選遞增)和View還是捆綁在一起(就是在元件裡面使用dispatch)這個方法是不可取的。所以下一步我們就要進一步優化我們的程式碼

檔案位置: app/redux_lesson/lesson_0.js

`use strict`

import React from `react`
import { createStore } from `redux`
import { Provider,connect } from `react-redux`

import Index from `../component/index`
import reducers from `../redux/reducer`
/*
    注意:這裡是新增的
    相對原來,我們在最外層打包這裡引入Action
*/
import {increaseAction} from `../redux/action`

//建立store
let store = createStore(reducers)
/*
  mapStateToProps你可以理解成在下面connect的時候提供一個state
*/
let mapStateToProps = (state) =>{
    return {count:state.count}
}
/*
    注意:這裡是新增的
    mapDispatchToProps你可以理解成在下面connect的時候提供一個放置好鑰匙的函式onIncreaseClick,直接呼叫就可以去reducer修改state了
*/
let mapDispatchToProps = (dispatch) =>{
    return{onIncreaseClick:()=>dispatch(increaseAction)}
}
/*
    注意:這裡是修改了的
    連線你的state和最外層的元件
*/
let Content = connect(mapStateToProps,mapDispatchToProps)(Index)

let {Component} = React

//使用Provider來把新的App元件打包出來
class App extends Component{
    render(){
        return <Provider store={store}><Content /></Provider>
    }
}

export default App

檔案位置: app/compoment/index.js

`use strict`

import React from `react`
import { connect } from `react-redux`
/*
    注意:這裡是修改樂的
    現在不用引入action了,因為前一步已經把鑰匙Action放到相應的函式中去,作為props傳入元件裡面
*/
//import {increaseAction} from `../redux/action`
let {Component,PropTypes}  = React
class Index extends Component{
    //這一步是檢查傳入的各個prop型別是否正確
    ProTypes = {
        count:PropTypes.number.isRequired,
        onIncreaseClick:PropTypes.func.isRequired,
    }
    constructor(props){
        super(props)
    }
    handleClick(){
        /*
            注意:這裡是修改過的
            現在,我們把打包好的,帶著鑰匙的函式進行呼叫
        */
        console.log(this.props)
        let {onIncreaseClick} = this.props
        onIncreaseClick()
    }
    render(){
        let {count} = this.props
        return <div onClick = {this.handleClick.bind(this)}  style={styles.circle}>{count}</div>
    }
}
//樣式檔案,不用細看
...(以下相同就略去)

結語

redux其實不難理解,按照我個人理解的加工工廠模式:有一家大公司叫做store,裡面有工廠(reducer),公司(store)只有一家,但這家公司(store)可以有很多工廠(reducer)。要進去工廠加工產品(state),就得帶上相應得鑰匙(Action),不同的鑰匙(Action)對應工廠中上不同的生產線(redecer裡面的switch函式),從而有不同的產出(改變之後的state)

相關文章