React-redux使用

1.actionCreator

// action creator 就是函數而已...
var actionCreator = function() {
    // ...負責構建一個 action (是的,action creator 這個名字已經很明顯了)並返回它
    return {
        type: 'AN_ACTION'
    }
}

2.store

import { createStore } from 'redux';
var store = createStore(() => {});//createStore 函數必須接收一個能夠修改應用狀態的函數

3.reducer

import { createStore } from 'redux';
var store_0 = createStore(() => {});
var reducer = function (...args) {
    console.log('Reducer was called with args', args)
};
var store_1 = createStore(reducer);

4.get-state

import { createStore } from 'redux'
var reducer_0 = function (state, action) {
    console.log('reducer_0 was called with state', state, 'and action', action)
}
var store_0 = createStore(reducer_0)
// 輸出: reducer_0 was called with state undefined and action { type: '@@redux/INIT' }
// 爲了讀取 Redux 保存的 state,你可以調用 getState
console.log('store_0 state after initialization:', store_0.getState())
// 輸出: store_0 state after initialization: undefined
/*-----------------------------------------------*/
var reducer_3 = function (state = {}, action) {
    console.log('reducer_3 was called with state', state, 'and action', action)
    switch (action.type) {
        case 'SAY_SOMETHING':
            return {
                ...state,
                message: action.value
            }
        default:
            return state;
    }
}
var store_3 = createStore(reducer_3)
// 輸出: reducer_3 was called with state {} and action { type: '@@redux/INIT' }
console.log('store_3 state after initialization:', store_3.getState())
// 輸出: store_3 state after initialization: {}

5.combine-reducers

var userReducer = function (state = {}, action) {
    console.log('userReducer was called with state', state, 'and action', action)
    switch (action.type) {
        // etc.
        default:
            return state;
    }
}
var itemsReducer = function (state = [], action) {
    console.log('itemsReducer was called with state', state, 'and action', action)
    switch (action.type) {
        // etc.
        default:
            return state;
    }
}
/*--------------------------------------*/
import { createStore, combineReducers } from 'redux'
var reducer = combineReducers({
    user: userReducer,
    items: itemsReducer
})
var store_0 = createStore(reducer)
// 輸出:
// userReducer was called with state {} and action { type: '@@redux/INIT' }
// itemsReducer was called with state [] and action { type: '@@redux/INIT' }

// 正如你從輸出中看到的,每個 reducer 都被正確地調用了(但接收了個 init action @@redux/INIT )。
// 這個 action 是什麼鬼?這是 combineReducers 實施的一次安全檢查,用以確保 reducer 永遠不會返回
// undefined。請注意,在 combineReducers 中第一次調用 init action 時,其實是隨機 action 來的,
// 但它們有個共同的目的 (即是做一個安全檢查)。

console.log('store_0 state after initialization:', store_0.getState())
// 輸出:
// store_0 state after initialization: { user: {}, items: [] }

6.dispatch-action(常用的同步action)

var userReducer = function (state = {}, action) {
    console.log('userReducer was called with state', state, 'and action', action)
    switch (action.type) {
        case 'SET_NAME':
            return {
                ...state,
                name: action.name
            }
        default:
            return state;
    }
}
var itemsReducer = function (state = [], action) {
    console.log('itemsReducer was called with state', state, 'and action', action)
    switch (action.type) {
        case 'ADD_ITEM':
            return [
                ...state,
                action.item
            ]
        default:
            return state;
    }
}
import { createStore, combineReducers } from 'redux'
var reducer = combineReducers({
    user: userReducer,
    items: itemsReducer
})
var store_0 = createStore(reducer)
console.log('store_0 state after initialization:', store_0.getState())
// 輸出:
// store_0 state after initialization: { user: {}, items: [] }
store_0.dispatch({
    type: 'AN_ACTION'
})
// 輸出:
// userReducer was called with state {} and action { type: 'AN_ACTION' }
// itemsReducer was called with state [] and action { type: 'AN_ACTION' }
// 每一個 reducer 都被調用了,但是沒有一個 action type 是 reducer 需要的,
// 因此 state 是不會發生變化的:
console.log('store_0 state after action AN_ACTION:', store_0.getState())
// 輸出:store_0 state after action AN_ACTION: { user: {}, items: [] }
// 但是,等一下!我們是不是可以用一個 action creator 去發送一個 action?我們確實可以
// 用一個 actionCreator,但由於它只是返回一個 action,那麼就意味着它不會攜帶任何東西
// 到這個例子中。但爲了面對未來遇到的困難,我們還是以正確的方式,
// 即以 flux 理論去做吧。讓我們使用這個 action creator 發送一個我們想要的 action:
var setNameActionCreator = function (name) {
    return {
        type: 'SET_NAME',
        name: name
    }
}
store_0.dispatch(setNameActionCreator('bob'))
// 輸出:
// userReducer was called with state {} and action { type: 'SET_NAME', name: 'bob' }
// itemsReducer was called with state [] and action { type: 'SET_NAME', name: 'bob' }
console.log('store_0 state after action SET_NAME:', store_0.getState())
// 輸出:
// store_0 state after action SET_NAME: { user: { name: 'bob' }, items: [] }

7.dispatch-async-action

import { createStore, combineReducers } from 'redux'
var reducer = combineReducers({
    speaker: function (state = {}, action) {
        console.log('speaker was called with state', state, 'and action', action)
        switch (action.type) {
            case 'SAY':
                return {
                    ...state,
                    message: action.message
                }
            default:
                return state;
        }
    }
})
var store_0 = createStore(reducer)
var sayActionCreator = function (message) {
    return {
        type: 'SAY',
        message
    }
}
console.log("\n", 'Running our normal action creator:', "\n")
console.log(new Date());
store_0.dispatch(sayActionCreator('Hi'))
console.log(new Date());
console.log('store_0 state after action SAY:', store_0.getState())
// 輸出(忽略初始輸出):
//     Sun Aug 02 2015 01:03:05 GMT+0200 (CEST)
//     speaker was called with state {} and action { type: 'SAY', message: 'Hi' }
//     Sun Aug 02 2015 01:03:05 GMT+0200 (CEST)
//     store_0 state after action SAY: { speaker: { message: 'Hi' } }
// ... 結果 store 被立即更新了。
// 我們希望看到的結果應該類似於下面這樣的代碼:
var asyncSayActionCreator_0 = function (message) {
    setTimeout(function () {
        return {
            type: 'SAY',
            message
        }
    }, 2000)
}
// 但是這樣 action creator 返回的不是 action 而是 undefined。所以這並不是我們所期望的解決方法。
// 這裏有個訣竅:不返回 action,而是返回 function。這個 function 會在合適的時機 dispatch action。但是如果我們希望
// 這個 function 能夠 dispatch action,那麼就需要向它傳入 dispatch 函數。於是代碼類似如下:
var asyncSayActionCreator_1 = function (message) {
    return function (dispatch) {
        setTimeout(function () {
            dispatch({
                type: 'SAY',
                message
            })
        }, 2000)
    }
}
/*===============================================*/
import { createStore, combineReducers } from 'redux'
var reducer = combineReducers({
    speaker: function (state = {}, action) {
        console.log('speaker was called with state', state, 'and action', action)

        switch (action.type) {
            case 'SAY':
                return {
                    ...state,
                    message: action.message
                }
            default:
                return state;
        }
    }
})
var store_0 = createStore(reducer)
var asyncSayActionCreator_1 = function (message) {
    return function (dispatch) {
        setTimeout(function () {
            dispatch({
                type: 'SAY',
                message
            })
        }, 2000)
    }
}
console.log("\n", 'Running our async action creator:', "\n")
store_0.dispatch(asyncSayActionCreator_1('Hi'))
// 輸出:
//     ...
//     /Users/classtar/Codes/redux-tutorial/node_modules/redux/node_modules/invariant/invariant.js:51
//         throw error;
//               ^
//     Error: Invariant Violation: Actions must be plain objects. Use custom middleware for async actions.
//     ...

8.middleware(中間件)

// 通常來說中間件是在某個應用中 A 和 B 部分中間的那一塊,
// 中間件可以把 A 發送數據到 B 的形式從
// A -----> B
// 變成:
// A ---> middleware 1 ---> middleware 2 ---> middleware 3 --> ... ---> B
// 適合 Redux 處理的內容middleware工作原理:
// action ---> dispatcher ---> middleware 1 ---> middleware 2 ---> reducers
/*-----------------------------------------------*/
// 如上所述,中間件由三個嵌套的函數構成(會依次調用):
// 1) 第一層向其餘兩層提供分發函數和 getState 函數
//    (因爲你的中間件或 action creator 可能需要從 state 中讀取數據)
// 2) 第二層提供 next 函數,它允許你顯式的將處理過的輸入傳遞給下一個中間件或 Redux
//    (這樣 Redux 才能調用所有 reducer)。
// 3) 第三層提供從上一個中間件或從 dispatch 傳遞來的 action,
//     這個 action 可以調用下一個中間件(讓 action 繼續流動) 或者
//     以想要的方式處理 action。
// 我們爲異步 action creator 提供的中間件叫 thunk middleware
// 它的代碼在:https://github.com/gaearon/redux-thunk.
// 它看上去是這樣 (爲了可讀性使用 ES5 語法書寫該函數):
var thunkMiddleware = function ({ dispatch, getState }) {
    // console.log('Enter thunkMiddleware');
    return function(next) {
        // console.log('Function "next" provided:', next);
        return function (action) {
            // console.log('Handling action:', action);
            return typeof action === 'function' ?
                action(dispatch, getState) :
                next(action)
        }
    }
}
// 爲了讓 Redux 知道我們有一個或多箇中間件,我們使用 Redux 的
// 輔助函數:applyMiddleware.
// applyMiddleware 接收所有中間件作爲參數,返回一個供 Redux createStore 調用的函數。
// 當最後這個函數被調用時,它會產生一個 Store 增強器,用來將所有中間件應用到 Store 的 dispatch 上。
// (來自 https://github.com/rackt/redux/blob/v1.0.0-rc/src/utils/applyMiddleware.js)
// 下面就是如何將一箇中間件應用到 Redux store:
import { createStore, combineReducers, applyMiddleware } from 'redux'
const finalCreateStore = applyMiddleware(thunkMiddleware)(createStore)
// 針對多箇中間件, 使用:applyMiddleware(middleware1, middleware2, ...)(createStore)
var reducer = combineReducers({
    speaker: function (state = {}, action) {
        console.log('speaker was called with state', state, 'and action', action)

        switch (action.type) {
            case 'SAY':
                return {
                    ...state,
                    message: action.message
                }
            default:
                return state
        }
    }
})
const store_0 = finalCreateStore(reducer)
// 輸出:
//     speaker was called with state {} and action { type: '@@redux/INIT' }
//     speaker was called with state {} and action { type: '@@redux/PROBE_UNKNOWN_ACTION_s.b.4.z.a.x.a.j.o.r' }
//     speaker was called with state {} and action { type: '@@redux/INIT' }
// 現在 store 的 middleware 已經準備好了,再來嘗試分發我們的異步 action:
var asyncSayActionCreator_1 = function (message) {
    return function (dispatch) {
        setTimeout(function () {
            console.log(new Date(), 'Dispatch action now:')
            dispatch({
                type: 'SAY',
                message
            })
        }, 2000)
    }
}
console.log("\n", new Date(), 'Running our async action creator:', "\n")
store_0.dispatch(asyncSayActionCreator_1('Hi'))
// 輸出:
//     Mon Aug 03 2015 00:01:20 GMT+0200 (CEST) Running our async action creator:
//     Mon Aug 03 2015 00:01:22 GMT+0200 (CEST) 'Dispatch action now:'
//     speaker was called with state {} and action { type: 'SAY', message: 'Hi' }
// 當我們調用異步 action creator 兩秒之後,action 成功被分發出去。
// 你可能會好奇,一箇中間件如何 log 出所有已分發的 action ,
// 是這樣:
function logMiddleware ({ dispatch, getState }) {
    return function(next) {
        return function (action) {
            console.log('logMiddleware action received:', action)
            return next(action)
        }
    }
}
// 同樣的,下面是一箇中間件,它會丟棄所有經過的 action(不是很實用,
// 但是如果加一些判斷就能實現丟棄一些 action,放到一些 action 給下一個中間件):
function discardMiddleware ({ dispatch, getState }) {
    return function(next) {
        return function (action) {
            console.log('discardMiddleware action received:', action)
        }
    }
}

9.subscriber(訂閱 state 的更新)

import { createStore, combineReducers } from 'redux'
var itemsReducer = function (state = [], action) {
    console.log('itemsReducer was called with state', state, 'and action', action)
    switch (action.type) {
        case 'ADD_ITEM':
            return [
                ...state,
                action.item
            ]
        default:
            return state;
    }
}
var reducer = combineReducers({ items: itemsReducer })
var store_0 = createStore(reducer)
store_0.subscribe(function() {
    console.log('store_0 has been updated. Latest store state:', store_0.getState());
    // 在這裏更新你的視圖
})
var addItemActionCreator = function (item) {
    return {
        type: 'ADD_ITEM',
        item: item
    }
}
store_0.dispatch(addItemActionCreator({ id: 1234, description: 'anything' }))
// 但是最後我們還是需要一個更好的接口訂閱我們的 store變化。這也就是 react-redux 給帶給我們的:
// 一個完美填補原生 Redux 訂閱機制和開發者的期待之間的空缺的 API ,
// 這樣我們不再需要直接使用訂閱。而只是
// 使用 “provide” 和 ”connect“ 綁定,不必再關心隱含在內的訂閱方法。

10.Provider-and-connect

import React from 'react'
import Home from './home'
import { Provider } from 'react-redux'
export default class Application extends React.Component {
  render () {
    return (
      // As explained above, the Provider must wrap your application's Root component. This way,
      // this component and all of its children (even deeply nested ones) will have access to your
      // Redux store. Of course, to allow Provider to do that, you must give it the store
      // you built previously (via a "store" props).
      <Provider store={ this.props.store }>
        <Home />
      </Provider>
    )
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章