成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

大話Redux

Soarkey / 904人閱讀

摘要:就是發(fā)出的通知,表示應(yīng)該要發(fā)生變化了。其中的屬性是必須的,表示的名稱。不同的函數(shù)負(fù)責(zé)處理不同屬性,最終把它們合并成一個大的即可。上面的代碼通過方法將三個子合并成一個大的函數(shù)。該函數(shù)根據(jù)的去執(zhí)行相應(yīng)的子,并將返回結(jié)果合并成一個大的對象。

一、什么是Redux

Redux 的設(shè)計(jì)思想很簡單,就兩句話。

(1)Web 應(yīng)用是一個狀態(tài)機(jī),視圖與狀態(tài)是一一對應(yīng)的。

(2)所有的狀態(tài),保存在一個對象里面。

二、基本概念和API 1. Store

Store 就是保存數(shù)據(jù)的地方,你可以把它看成一個容器。整個應(yīng)用只能有一個 Store。

Redux 提供createStore這個函數(shù),用來生成 Store。

import { createStore } from "redux";
const store = createStore(fn);

上面代碼中,createStore函數(shù)接受另一個函數(shù)作為參數(shù),返回新生成的 Store 對象。

2. State

Store對象包含所有數(shù)據(jù)。如果想得到某個時(shí)點(diǎn)的數(shù)據(jù),就要對 Store 生成快照。這種時(shí)點(diǎn)的數(shù)據(jù)集合,就叫做 State。

當(dāng)前時(shí)刻的 State,可以通過store.getState()拿到。

import { createStore } from "redux";
const store = createStore(fn);

const state = store.getState();

Redux 規(guī)定, 一個 State 對應(yīng)一個 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么樣,反之亦然。

3. Action

State 的變化,會導(dǎo)致 View 的變化。但是,用戶接觸不到 State,只能接觸到 View。所以,State 的變化必須是 View 導(dǎo)致的。Action 就是 View 發(fā)出的通知,表示 State 應(yīng)該要發(fā)生變化了。

Action 是一個對象。其中的type屬性是必須的,表示 Action 的名稱。其他屬性可以自由設(shè)置,社區(qū)有一個規(guī)范可以參考。

const action = {
  type: "ADD_TODO",
  payload: "Learn Redux"
};

上面代碼中,Action 的名稱是ADD_TODO,它攜帶的信息是字符串Learn Redux。

可以這樣理解,Action 描述當(dāng)前發(fā)生的事情。改變 State 的唯一辦法,就是使用 Action。它會運(yùn)送數(shù)據(jù)到 Store。

4. Action Creator

View 要發(fā)送多少種消息,就會有多少種 Action。如果都手寫,會很麻煩。可以定義一個函數(shù)來生成 Action,這個函數(shù)就叫 Action Creator。

const ADD_TODO = "添加 TODO";

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

const action = addTodo("Learn Redux");
上面代碼中,addTodo函數(shù)就是一個 Action Creator。

5. store.dispatch()

store.dispatch()是 View 發(fā)出 Action 的唯一方法。

import { createStore } from "redux";
const store = createStore(fn);

store.dispatch({
  type: "ADD_TODO",
  payload: "Learn Redux"
});

上面代碼中,store.dispatch接受一個 Action 對象作為參數(shù),將它發(fā)送出去。

結(jié)合 Action Creator,這段代碼可以改寫如下。

store.dispatch(addTodo("Learn Redux"));
6. Reducer

Store 收到 Action 以后,必須給出一個新的 State,這樣 View 才會發(fā)生變化。這種 State 的計(jì)算過程就叫做 Reducer。

Reducer 是一個函數(shù),它接受 Action 和當(dāng)前 State 作為參數(shù),返回一個新的 State。

const reducer = function (state, action) {
  // ...
  return new_state;
};

整個應(yīng)用的初始狀態(tài),可以作為 State 的默認(rèn)值。下面是一個實(shí)際的例子。

const defaultState = 0;
const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case "ADD":
      return state + action.payload;
    default: 
      return state;
  }
};

const state = reducer(1, {
  type: "ADD",
  payload: 2
});

上面代碼中,reducer函數(shù)收到名為ADD的 Action 以后,就返回一個新的 State,作為加法的計(jì)算結(jié)果。其他運(yùn)算的邏輯(比如減法),也可以根據(jù) Action 的不同來實(shí)現(xiàn)。

實(shí)際應(yīng)用中,Reducer 函數(shù)不用像上面這樣手動調(diào)用,store.dispatch方法會觸發(fā) Reducer 的自動執(zhí)行。為此,Store 需要知道 Reducer 函數(shù),做法就是在生成 Store 的時(shí)候,將 Reducer 傳入createStore方法。

import { createStore } from "redux";
const store = createStore(reducer);

上面代碼中,createStore接受 Reducer 作為參數(shù),生成一個新的 Store。以后每當(dāng)store.dispatch發(fā)送過來一個新的 Action,就會自動調(diào)用 Reducer,得到新的 State。

為什么這個函數(shù)叫做 Reducer 呢?因?yàn)樗梢宰鳛閿?shù)組的reduce方法的參數(shù)。請看下面的例子,一系列 Action 對象按照順序作為一個數(shù)組。

const actions = [
  { type: "ADD", payload: 0 },
  { type: "ADD", payload: 1 },
  { type: "ADD", payload: 2 }
];

const total = actions.reduce(reducer, 0); // 3

上面代碼中,數(shù)組actions表示依次有三個 Action,分別是加0、加1和加2。數(shù)組的reduce方法接受 Reducer 函數(shù)作為參數(shù),就可以直接得到最終的狀態(tài)3

7. 純函數(shù)

Reducer 函數(shù)最重要的特征是,它是一個純函數(shù)。也就是說,只要是同樣的輸入,必定得到同樣的輸出。

純函數(shù)是函數(shù)式編程的概念,必須遵守以下一些約束。

不得改寫參數(shù)
不能調(diào)用系統(tǒng) I/O 的API
不能調(diào)用Date.now()或者M(jìn)ath.random()等不純的方法,因?yàn)槊看螘玫讲灰粯拥慕Y(jié)果

由于 Reducer 是純函數(shù),就可以保證同樣的State,必定得到同樣的 View。但也正因?yàn)檫@一點(diǎn),Reducer 函數(shù)里面不能改變 State,必須返回一個全新的對象,請參考下面的寫法。

// State 是一個對象
function reducer(state, action) {
  return Object.assign({}, state, { thingToChange });
  // 或者
  return { ...state, ...newState };
}

// State 是一個數(shù)組
function reducer(state, action) {
  return [...state, newItem];
}

最好把 State 對象設(shè)成只讀。你沒法改變它,要得到新的 State,唯一辦法就是生成一個新對象。這樣的好處是,任何時(shí)候,與某個 View 對應(yīng)的 State 總是一個不變的對象。

8. store.subscribe()

Store 允許使用store.subscribe方法設(shè)置監(jiān)聽函數(shù),一旦 State 發(fā)生變化,就自動執(zhí)行這個函數(shù)。

import { createStore } from "redux";
const store = createStore(reducer);

store.subscribe(listener);

顯然,只要把 View 的更新函數(shù)(對于 React 項(xiàng)目,就是組件的render方法或setState方法)放入listen,就會實(shí)現(xiàn) View 的自動渲染。

store.subscribe方法返回一個函數(shù),調(diào)用這個函數(shù)就可以解除監(jiān)聽。

let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
);

unsubscribe();

三、Store 的實(shí)現(xiàn)

上一節(jié)介紹了 Redux 涉及的基本概念,可以發(fā)現(xiàn) Store 提供了三個方法。

store.getState()
store.dispatch()
store.subscribe()

import { createStore } from "redux";
let { subscribe, dispatch, getState } = createStore(reducer);

createStore方法還可以接受第二個參數(shù),表示 State 的最初狀態(tài)。這通常是服務(wù)器給出的。

let store = createStore(todoApp, window.STATE_FROM_SERVER)

上面代碼中,window.STATE_FROM_SERVER就是整個應(yīng)用的狀態(tài)初始值。注意,如果提供了這個參數(shù),它會覆蓋 Reducer 函數(shù)的默認(rèn)初始值。

下面是createStore方法的一個簡單實(shí)現(xiàn),可以了解一下 Store 是怎么生成的。

const createStore = (reducer) => {
  let state;
  let listeners = [];

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  };

  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(l => l !== listener);
    }
  };

  dispatch({});

  return { getState, dispatch, subscribe };
};
四、Reducer 的拆分

Reducer 函數(shù)負(fù)責(zé)生成 State。由于整個應(yīng)用只有一個 State 對象,包含所有數(shù)據(jù),對于大型應(yīng)用來說,這個 State 必然十分龐大,導(dǎo)致 Reducer 函數(shù)也十分龐大。

請看下面的例子。

const chatReducer = (state = defaultState, action = {}) => {
  const { type, payload } = action;
  switch (type) {
    case ADD_CHAT:
      return Object.assign({}, state, {
        chatLog: state.chatLog.concat(payload)
      });
    case CHANGE_STATUS:
      return Object.assign({}, state, {
        statusMessage: payload
      });
    case CHANGE_USERNAME:
      return Object.assign({}, state, {
        userName: payload
      });
    default: return state;
  }
};

上面代碼中,三種 Action 分別改變 State 的三個屬性。

ADD_CHAT:chatLog屬性
CHANGE_STATUS:statusMessage屬性
CHANGE_USERNAME:userName屬性

這三個屬性之間沒有聯(lián)系,這提示我們可以把 Reducer 函數(shù)拆分。不同的函數(shù)負(fù)責(zé)處理不同屬性,最終把它們合并成一個大的 Reducer 即可。

const chatReducer = (state = defaultState, action = {}) => {
  return {
    chatLog: chatLog(state.chatLog, action),
    statusMessage: statusMessage(state.statusMessage, action),
    userName: userName(state.userName, action)
  }
};

上面代碼中,Reducer 函數(shù)被拆成了三個小函數(shù),每一個負(fù)責(zé)生成對應(yīng)的屬性。

這樣一拆,Reducer 就易讀易寫多了。而且,這種拆分與 React 應(yīng)用的結(jié)構(gòu)相吻合:一個 React 根組件由很多子組件構(gòu)成。這就是說,子組件與子 Reducer 完全可以對應(yīng)。

Redux 提供了一個combineReducers方法,用于 Reducer 的拆分。你只要定義各個子 Reducer 函數(shù),然后用這個方法,將它們合成一個大的 Reducer。

import { combineReducers } from "redux";

const chatReducer = combineReducers({
  chatLog,
  statusMessage,
  userName
})

export default todoApp;

上面的代碼通過combineReducers方法將三個子 Reducer 合并成一個大的函數(shù)。

這種寫法有一個前提,就是 State 的屬性名必須與子 Reducer 同名。如果不同名,就要采用下面的寫法。

const reducer = combineReducers({
  a: doSomethingWithA,
  b: processB,
  c: c
})

// 等同于
function reducer(state = {}, action) {
  return {
    a: doSomethingWithA(state.a, action),
    b: processB(state.b, action),
    c: c(state.c, action)
  }
}

總之,combineReducers()做的就是產(chǎn)生一個整體的 Reducer 函數(shù)。該函數(shù)根據(jù) State 的 key 去執(zhí)行相應(yīng)的子 Reducer,并將返回結(jié)果合并成一個大的 State 對象。

下面是combineReducer的簡單實(shí)現(xiàn)。

const combineReducers = reducers => {
  return (state = {}, action) => {
    return Object.keys(reducers).reduce(
      (nextState, key) => {
        nextState[key] = reducers[key](state[key], action);
        return nextState;
      },
      {} 
    );
  };
};

你可以把所有子 Reducer 放在一個文件里面,然后統(tǒng)一引入。

import { combineReducers } from "redux"
import * as reducers from "./reducers"

const reducer = combineReducers(reducers)
五、工作流程

本節(jié)對 Redux 的工作流程,做一個梳理。

首先,用戶發(fā)出 Action。

store.dispatch(action);

然后,Store 自動調(diào)用 Reducer,并且傳入兩個參數(shù):當(dāng)前 State 和收到的 Action。 Reducer 會返回新的 State 。

let nextState = todoApp(previousState, action);

State 一旦有變化,Store 就會調(diào)用監(jiān)聽函數(shù)。

// 設(shè)置監(jiān)聽函數(shù)
store.subscribe(listener);

listener可以通過store.getState()得到當(dāng)前狀態(tài)。如果使用的是 React,這時(shí)可以觸發(fā)重新渲染 View。

function listerner() {
  let newState = store.getState();
  component.setState(newState);   
}
六、實(shí)例:計(jì)數(shù)器

下面我們來看一個最簡單的實(shí)例。

const Counter = ({ value }) => (
  

{value}

); const render = () => { ReactDOM.render( , document.getElementById("root") ); }; store.subscribe(render); render();

上面是一個簡單的計(jì)數(shù)器,唯一的作用就是把參數(shù)·value·的值,顯示在網(wǎng)頁上。Store 的監(jiān)聽函數(shù)設(shè)置為render,每次 State 的變化都會導(dǎo)致網(wǎng)頁重新渲染。

下面加入一點(diǎn)變化,為Counter添加遞增和遞減的 Action。

const Counter = ({ value, onIncrement, onDecrement }) => (
  

{value}

); const reducer = (state = 0, action) => { switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } }; const store = createStore(reducer); const render = () => { ReactDOM.render( store.dispatch({type: "INCREMENT"})} onDecrement={() => store.dispatch({type: "DECREMENT"})} />, document.getElementById("root") ); }; render(); store.subscribe(render);

如果你覺得這篇文章對你有所幫助,那就順便點(diǎn)個贊吧,點(diǎn)點(diǎn)關(guān)注不迷路~

黑芝麻哇,白芝麻發(fā),黑芝麻白芝麻哇發(fā)哈!

前端哇發(fā)哈

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/109603.html

相關(guān)文章

  • 大話React-Redux

    摘要:一組件將所有組件分成兩大類組件和容器組件。前者負(fù)責(zé)與外部的通信,將數(shù)據(jù)傳給后者,由后者渲染出視圖。也就是說,用戶負(fù)責(zé)視覺層,狀態(tài)管理則是全部交給它。前者需要從計(jì)算得到,后者需要向外發(fā)出。最后,生成對象,并使用在根組件外面包一層。 一、UI 組件 React-Redux 將所有組件分成兩大類:UI 組件(presentational component)和容器組件(container c...

    huangjinnan 評論0 收藏0
  • 大話WEB開發(fā)》

    摘要:作為開發(fā)者,需要不斷的對技術(shù)點(diǎn)進(jìn)行總結(jié),并且把它沉淀下來,寫技術(shù)博文無疑是最好的方式,隨著時(shí)間流逝,還可以作為自己每個階段的技術(shù)認(rèn)知軌跡進(jìn)行回顧和反思,這里將會持續(xù)記錄對開發(fā)相關(guān)總結(jié)內(nèi)容后端開發(fā)大話后端開發(fā)的奇淫技巧大集合高并發(fā)大話程序猿眼 作為WEB開發(fā)者,需要不斷的對技術(shù)點(diǎn)進(jìn)行總結(jié),并且把它沉淀下來,寫技術(shù)博文無疑是最好的方式,隨著時(shí)間流逝,還可以作為自己每個階段的技術(shù)認(rèn)知軌跡進(jìn)行...

    ytwman 評論0 收藏0
  • 大話WEB開發(fā)》

    摘要:作為開發(fā)者,需要不斷的對技術(shù)點(diǎn)進(jìn)行總結(jié),并且把它沉淀下來,寫技術(shù)博文無疑是最好的方式,隨著時(shí)間流逝,還可以作為自己每個階段的技術(shù)認(rèn)知軌跡進(jìn)行回顧和反思,這里將會持續(xù)記錄對開發(fā)相關(guān)總結(jié)內(nèi)容后端開發(fā)大話后端開發(fā)的奇淫技巧大集合高并發(fā)大話程序猿眼 作為WEB開發(fā)者,需要不斷的對技術(shù)點(diǎn)進(jìn)行總結(jié),并且把它沉淀下來,寫技術(shù)博文無疑是最好的方式,隨著時(shí)間流逝,還可以作為自己每個階段的技術(shù)認(rèn)知軌跡進(jìn)行...

    zsirfs 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<