Redux讓我腦仁疼,感受搞不定他。由於Redux對我而言太抽象了,因此我用通俗易懂地方法去思考Redux,感受可以理解Redux一些了。node
本文要點:git
本文代碼倉庫,在此文件夾之中。es6
講道理我要用import和export的寫法來學習Redux,可是node有些es6仍是不支持的,爲了簡單演示,我就用requre和module.exports來演示。(否則我還得講解下babel轉換es6的知識點)github
在開始以前,咱們是否是應該安裝一個redux,而後才能開始愉快地玩耍。npm
npm install --save redux
複製代碼
用Redux建立全局應用數據管理store
以前,咱們須要建立兩個類型的JS文件,一個是action
一個是reducer
,這兩個類型的功能我我的認爲很容易搞混。不知道哪一個是幹什麼,常常忘記用法。那我只能經過他們的具體含義來判斷他們的用法,而不是死記硬背(哎,年紀大了,記性很差,只能經過理解來記住了。)redux
首先咱們先看action
,相信這個單詞你們都認識。導演拍戲的時候,都喜歡說action!
,這個既有行動的意思,也有開始的意思,在Redux中就是開始行動的意思。也就是說這個action是主動,而非被動的。導演說開始,你就要開始,並且還要按照劇本進行,一切都被安排地明明白白。因此,Redux的action,就是一個指示,告訴store,我要進行這個東西,你給安排下。有時候,咱們須要附帶點內容到store,才能進行下一步操做,這個時候就須要action攜帶規範的參數。數組
因此咱們怎麼寫action呢?包含兩點:bash
註冊行爲,安排行爲,標準每一個行爲的指令babel
const todo={
TOGGLE_TODO:'TOGGLE_TODO',
GET_TODOS:'GET_TODOS'
}
複製代碼
配置行爲所帶的參數,標準化參數,該帶上的都帶上,以避免被退回。其中type
是行爲的類型,必須有,就像有些office要帶門卡同樣,忘了就再見!要被保安請出去的。後方的item
就是自定義的,看看你的操做須要哪些參數,須要就帶上,不須要帶上的就不要帶上了,哪樣就很累贅了。異步
const todo={
TOGGLE_TODO:'TOGGLE_TODO',
GET_TODOS:'GET_TODOS',
toggleTodo:function ({ items,id }) {
return {
type: todo.TOGGLE_TODO,
items:items
id:id
}
},
getTodos: function getTodos({items}){
return {
type:todo.GET_TODOS,
items:items
}
}
}
module.exports=todo
複製代碼
action只是告訴你發生了什麼,給你配齊了參數,可是不執行,不對傳入的對象(state)進行改變。*
可是既然action僅僅是配置而已,那麼怎麼操做呢,以後怎麼進行呢?Redux纔不會這麼好心幫咱們把後續操做給搞定了,這個時候咱們就要去研究Reducer了,一個我不知道如何翻譯的函數。
如今咱們來看最沒法理解的reducer
,爲何他要叫reducer
,有什麼具體含義嗎?仍是隨便起的名字,總有一個緣由吧,就和爸媽給咱們取名字同樣老是寄予一些美好的期盼。
reducer
的含義有不少,不少領域都用這個單詞,可是在Redux中,這應該是函數式語言(functional languages)
中的一個概念。在wiki中,一般稱爲Fold,做爲一個結構轉變(structural transformations)的一個方式。
其餘語言Reducer實現方式咱們無論,咱們只看JS,在JS中出現的array.reduce(func,initval)
,相信你們應該很熟悉,也是一個剛上手就想哭的一個方法。數組中的reduce
有什麼特色呢(不會用reduce的小夥伴,點擊這裏):
initval
func
方法,這個方法必須是純函數,既不改變傳入對象的屬性array
保持不變。從而能夠推論出Redux中的reducer
的特色:
state
你們可能對純函數(pure funciton)
有些模糊,函數還能pure??覺得是純牛奶呢??這裏的pure的意思就是他是乾乾淨淨的,毫無雜質。也就是一下兩點:
你們想深刻了解的話,雙手奉上wiki連接。
那麼咱們該怎麼寫呢?
你們複習下上面的action,reducer但是action配套的好兄弟,一個在前,一個在後並肩做戰。
reducer並非主動執行,而是被動執行的,來了一個action,而後reducer處理下。
簡而言之:reducer就是響應來自action的召喚,而後返回一個新的對象(state)。
首先先導入來自action的行爲,這行爲是被註冊的,是能夠執行的。
const {TOGGLE_TODO,GET_TODOS}=require('../actions/Todo')
複製代碼
reducer的一個定義就是必定有個初始值,這裏設置一個也就是以防萬一。
const initialState={}
複製代碼
重點來了,reducer開始過濾註冊的行爲們,而後每次都是一個個配對,趕上配對的,就執行對應的代碼,而後返回一個新的state
,若是輪了一邊發現這是未註冊的行爲,爲了防止這個行爲回去很差交代,就把原始的state
給他帶回去交差。
module.exports=function(state = initialState, action) {
switch(action.type){
case GET_TODOS:
return {todos:[...action.items]}
case TOGGLE_TODO://deleted=true
return {
todos:action.items.map((i)=>{
if(i.id===action.id){
return {
...i,
status:i.status===0?1:0
}
}else{
return {
...i
}
}
})
}
default:
return state;
}
}
複製代碼
reducer根據action的指令,進行一系列操做,可是不改變原有的傳入對象(state),而是返回一個新的對象(state)。也就是Reducer,進行純計算,沒有異步,沒有污染,出來的值沒有意外,就像1+1必定等於2同樣,而後返回一個嶄新嶄新的對象(state)!
雖action和reducer是一對基,配合默契,可是他們都是兩個獨立的模塊,怎麼醬他們連接起來,還須要一個橋樑。這個就是store
,redux中真正的老大,你們都要經過store來執行下一步的人任務,以及要遵從store派發下來的任務。
咱們先配置一個老大吧,todoDemoList
是假數據,你們懂的測試用。老大隻須要reducers這羣小弟來建幫派createStore
。action再幫派創建之初並沒有用處。
const {createStore}= require('../../node_modules/redux')
const todo = require('./reducers/Todo')
const {toggleTodo,getTodos} = require('./actions/Todo')
let todoDemoList=(new Array(20)).join("|").split("|").map((v,i)=>{
return {id:i,content:"demo"+(i+1),status:i%4===0?1:0}
})
const store=createStore(todo)
複製代碼
咱們的store究有何種能立呢?
掌控整個應用的數據state
,老大固然是掌控全局的啦,沒有什麼能瞞住他
若是想要訪問應用數據state
,那麼就要給store提申請,這個申請就是getState()
console.log(store.getState())//打印出來是一個空的{},固然啦!咱們都沒有給老大進貢,拿來的數據
複製代碼
dispatch(你的申請action)
。action終於出場啦!store.dispatch(getTodos({items:todoDemoList}))//給老大進貢
console.log(store.getState().todos[1])//有數據了
store.dispatch(toggleTodo({items:todoDemoList,id:1}))//修改某一個小羅羅
console.log(store.getState().todos[1])//修改爲功
複製代碼
subscribe(監視器listener)
看着你呢,小樣給我注意點。不過此刻要注意,咱們要把監聽器放在全部的dispatch
執行以前,否則就捕捉不到dispatch
了。要在一切還沒發生以前,就準備好,否則就要給小樣們鑽空子了。就像盜竊同樣,小偷已經偷完跑路了,你再裝監控,也逮不住這個小偷啊。store.subscribe(()=>{
console.log(store.getState())//監控這手下的一舉一動
})
複製代碼
store.subscribe()
的返回值,這個返回值是一個方法,就像這樣store.subscribe()()
let unsubscribe=store.subscribe(()=>{
console.log(store.getState())//監控這手下的一舉一動
})
store.dispatch(toggleTodo({items:todoDemoList,id:1}))//老大在watching,當心翼翼。
unsubscribe()//放了大家,出去浪吧
store.dispatch(toggleTodo({items:todoDemoList,id:1}))//竟然真的沒有再繼續監視我了,放飛自我。
複製代碼
combineReducers(小弟們)
一個幫派只能有一個老大!可是能夠有頗有小弟,每一個小弟各司其職。可是要將這些小弟統一管理起來,這個時候就要用combineReducers
了。
用相同的方法建立一個filterAction
,而後用combineReducers
一下,接下來就能夠愉快地合做了。
...
const filterAction = require('./reducers/filterAction')
const {showCompleted} = require('./actions/filterAction')
...
const rootReducer = combineReducers({todo: todo, filterAction: filterAction})
....
store.dispatch(showCompleted({items:todoDemoList}))//success執行啦!
複製代碼