Redux學習日誌(一)
Redux中文文檔:http://www.redux.org.cn/
阮一峯的網絡學習日誌:http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
Redux是js的狀態容器,提供可預測化狀態管理
Redux除了和React一起用之外還支持 其他界面庫
他體積小(2KB)而且沒有任何依賴
什麼時候使用
當UI層十分簡單,沒有很多互動,Redux就是不必要的,用了反而增加複雜性
- 用戶的使用方式十分簡單
- 用戶之間沒有寫作
- 不需要與服務器大量交互,也沒有使用websocket
- 視圖層(view)只是從單一的來源獲取數據
以上這些情況不需要使用
- 用戶使用方式複雜
- 不同的身份有不同的適用方式(會員 普通用戶)
- 多個用戶之間可協作(聊天室)
- 與服務器大量交互,使用websocket
- view要從多個來源獲取數據
以上這些情況可以使用
如果應用不復雜可以不用
redux的設計思想
一 web應用是一個狀態機,視圖與狀態一一對應
二 所有的狀態,都保存在一個對象裏
基本概念和API
store
store是保存數據的地方,整個應用只能有一個store
createStore函數可用來生成store
/*引入Redux*/
import { createStore } from "redux"
const store=createStore(fn)
- 1
- 2
- 3
state
store對象包含所有的數據,如果想要得到某個時間點的數據,就要對store生成快照,這種時點的集合就叫做state
/*引入Redux*/
import { createStore } from "redux";
const store=createStore(fn)
const state=store.getState();
- 1
- 2
- 3
- 4
- 5
一個state對應一個view
action
state的變換帶動view的變化。但是用戶接觸不到state,用戶接觸到的是view層,當view層發生變化,會發出action,也就是說action是view發出的通知,表示state應該要產生變化
action是一個對象,其中type屬性是必須的,表示action的名稱,其他屬性可自由設置,
const action={
type:"TODO", //action的名字
payload:"Rexux" //攜帶的信息是字符串 "Redxux"
}
- 1
- 2
- 3
- 4
action描述當前發生的事情,改變state是唯一的辦法,就是使用action,他會把數據運送到store
action creator
view要發送多少種信息,就會有多少種action,如果都手寫,比較的麻煩,可以定義一個函數來生成action,這個函數就是action creater
const ADD_TODO="添加 TODO";
function addtodo(params){
return {
type:ADD_TODO,
params
}
}
const action=addtodo("learn redux")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
addtodo函數就是一個 Action Creator
store.dispatch()
store.dispatch()是view發出action的唯一方法
import { createStore } from "redux";
const store=createStore(fn);
store.dispatch({
type:"ADD_TODO",
payload:"learn redux"
})
- 1
- 2
- 3
- 4
- 5
- 6
結合以上的addTodo函數,可簡寫成
store.dispatch(addTodo("learn Redux"))
- 1
Reducer
store收到action之後,必須給出一個新的state,這樣view纔會發生變化,這種計算過程就叫做Reducer
Reducer是一個函數,他接受action和當前的state作爲參數,返回新的state,
const reducer=function(state,action){
//
return new_state
}
這是一個例子
const defaultState=0;
const reducer=(state=defaultState,action)=>{
switch(action.type){
case "ADD":
return state+store.payload;
default:
return state;
}
}
//
const state=reducer(1,{
type:"ADD",
payload:2
})
//輸出3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
但在實際的應用中,並不會手動的調用Readucer,store.dispatch方法會觸發Readucer的自動執行。爲此,store、需要知道Readucer函數,所以需要在生成store的時候,將Readucer傳入createStore方法
import { createStore } from "redux"
const store=createStore(reducer);
//createStore接收Reducerr作爲參數,以後每當store.dispatch發送過來一個新的action,就會自動調用Readucer,得到新的State。
- 1
- 2
- 3
純函數
Reducer函數最重要的特徵,他是一個純函數。也就是說,只要是同樣的輸入,必定得到同樣的輸出
純函數是函數式編程的概念,必須遵守一下一些約束,
函數式編程:函數是一等公民
- 不得改寫參數
- 不能調用系統I/O的API
- 不能調用Math.random或Data.now,因爲每次得到的值不相同
store.subscribe()
store允許使用store.subscribe方法設置監聽函數,一旦state發生變化,就會自動執行這個函數
import {createStore} from "redux";
const store=createStore(reducer)
store.subscribe(listener)
- 1
- 2
- 3
- 4
只要把view的更新函數放入listen,就會實現view的自動渲染
store.subscribe方法返回一個函數,調用這個函數可以解除監聽
let unsubscribe=store.subscribe(()=>{
console.log(store.getState)
})
- 1
- 2
- 3
Store提供了三個方法
+ store.getState()
+ store.dispatch()
+ store.subscribe()
- 1
- 2
- 3
在引入redux的時候
import { createStore } from "redux";
let { subscribe,dispatch,getState } = createStore(reducer)
- 1
- 2
createStore可以接受第二個參數
let store=createStore(fn,window.STATE_FROM_SERVER)
- 1
window.STATE_FROM_SERVER就是整個應用的初始值,如果提供這個參數,他會覆蓋Reducer函數的初始默認值
createStore方法的實現
const createStore=(reducer)=>{
let state;
let listeners=[];
const getState=()=>state;
//dispatch是view發出的action的唯一方法
const dispatch=(action)=>{
state=reducer(state,action);
listeners.foreach(listener=>listener())
};
const subscripbe=(listener)=>{
listeners.push(listener);
return ()=>{
listeners=listeners.filter(1=>1!listener);
}
};
dispatch({});
return {getState,dsipatch,subscribe};
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
Reducer的拆分
Reducer可生成State,整個應用只有一個State對象,包含所有的數據,當State十分龐大的時候,Reducer函數也十分龐大。
例如
const chatReducer=(state=defaultState,action={})=>{
const {type,payload}=action;
switch (type){
case ADD_CHAT:
return Object.assign({},state,{
chatLog:state.chatLog.concat(payloiad)
});
case CHANGE_STATUS:
return Object.assign({},state,{
statusMessage:payload
});
case CHANGE_USERNAME:
return Object.assign({},state,{
userName:payload
});
default:return state;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
以上代碼中三種action分別改變state的三個屬性
- ADD_CHAT:chatlog屬性
- CHANGE_STATUS:statusMessage屬性
- CHANGE_USENAME:userName屬性
Reducer提供combineReducer方法,用於Reducer的拆分
import {combineReducers} from "redux";
const chatReducer=combineReducer({
chatLog:chatLog,
userName:userName
})
- 1
- 2
- 3
- 4
- 5
- 6
這段代碼的意思是combineReducer方法將三個Reducer合併成一個大的函數;