Redux學習(一)

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合併成一個大的函數;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章