Redux(基本用法)

React 只是 DOM 的一個抽象層,并不是 Web 應(yīng)用的完整解決方案墓捻。有兩個方面,它沒涉及环凿。

  • 代碼結(jié)構(gòu)
  • 組件之間的通信

對于大型的復(fù)雜應(yīng)用來說智听,這兩方面恰恰是最關(guān)鍵的到推。因此莉测,只用 React 沒法寫大型應(yīng)用捣卤。
為了解決這個問題董朝,2014年 Facebook 提出了 Flux 架構(gòu)的概念子姜,引發(fā)了很多的實現(xiàn)哥捕。2015年扭弧,Redux 出現(xiàn)鸽捻,將 Flux 與函數(shù)式編程結(jié)合一起御蒲,很短時間內(nèi)就成為了最熱門的前端架構(gòu)厚满。
本文詳細介紹 Redux 架構(gòu)碘箍,由于內(nèi)容較多货邓,全文分成三個部分换况。今天是第一部分戈二,介紹基本概念和用法觉吭。

Redux

零、你可能不需要 Redux


首先明確一點绒北,Redux 是一個有用的架構(gòu)闷游,但不是非用不可。事實上业簿,大多數(shù)情況梅尤,你可以不用它巷燥,只用 React 就夠了陨享。
曾經(jīng)有人說過這樣一句話抛姑。
"如果你不知道是否需要 Redux,那就是不需要它。"
Redux 的創(chuàng)造者 Dan Abramov 又補充了一句蒜茴。
"只有遇到 React 實在解決不了的問題粉私,你才需要 Redux 。"
簡單說窖杀,如果你的UI層非常簡單入客,沒有很多互動,Redux 就是不必要的铆隘,用了反而增加復(fù)雜性掏湾。

  • 用戶的使用方式非常簡單
  • 用戶之間沒有協(xié)作
  • 不需要與服務(wù)器大量交互,也沒有使用 WebSocket
  • 視圖層(View)只從單一來源獲取數(shù)據(jù)

上面這些情況砚嘴,都不需要使用 Redux。

  • 用戶的使用方式復(fù)雜
  • 不同身份的用戶有不同的使用方式(比如普通用戶和管理員)
  • 多個用戶之間可以協(xié)作
  • 與服務(wù)器大量交互工育,或者使用了WebSocket
  • View要從多個來源獲取數(shù)據(jù)

上面這些情況才是 Redux 的適用場景:多交互、多數(shù)據(jù)源。
從組件角度看扼脐,如果你的應(yīng)用有以下場景瓦侮,可以考慮使用 Redux。

  • 某個組件的狀態(tài),需要共享
  • 某個狀態(tài)需要在任何地方都可以拿到
  • 一個組件需要改變?nèi)譅顟B(tài)
  • 一個組件需要改變另一個組件的狀態(tài)

發(fā)生上面情況時坞生,如果不使用 Redux 或者其他狀態(tài)管理工具,不按照一定規(guī)律處理狀態(tài)的讀寫掷伙,代碼很快就會變成一團亂麻是己。你需要一種機制,可以在同一個地方查詢狀態(tài)任柜、改變狀態(tài)卒废、傳播狀態(tài)的變化沛厨。
總之,不要把 Redux 當(dāng)作萬靈丹摔认,如果你的應(yīng)用沒那么復(fù)雜逆皮,就沒必要用它。另一方面参袱,Redux 只是 Web 架構(gòu)的一種解決方案电谣,也可以選擇其他方案。

一抹蚀、預(yù)備知識


閱讀本文剿牺,你只需要懂 React。如果還懂 Flux环壤,就更好了晒来,會比較容易理解一些概念,但不是必需的郑现。
Redux 有很好的文檔湃崩,還有配套的小視頻(前30集后30集)接箫。你可以先閱讀本文攒读,再去官方材料詳細研究。
我的目標(biāo)是列牺,提供一個簡潔易懂的、全面的入門級參考文檔拗窃。

二瞎领、設(shè)計思想


Redux 的設(shè)計思想很簡單,就兩句話随夸。
(1)Web 應(yīng)用是一個狀態(tài)機九默,視圖與狀態(tài)是一一對應(yīng)的。
(2)所有的狀態(tài)宾毒,保存在一個對象里面驼修。
請務(wù)必記住這兩句話,下面就是詳細解釋诈铛。

三乙各、基本概念和 API


3.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 對象。

3.2 State


Store對象包含所有數(shù)據(jù)循签。如果想得到某個時點的數(shù)據(jù)级乐,就要對 Store 生成快照。這種時點的數(shù)據(jù)集合县匠,就叫做 State风科。
當(dāng)前時刻的 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.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。它會運送數(shù)據(jù)到 Store溉旋。

3.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倘核。

3.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'));

3.6 Reducer


Store 收到 Action 以后桩砰,必須給出一個新的 State拓春,這樣 View 才會發(fā)生變化痘儡。這種 State 的計算過程就叫做 Reducer沉删。
Reducer 是一個函數(shù),它接受 Action 和當(dāng)前 State 作為參數(shù)隘擎,返回一個新的 State货葬。

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

整個應(yīng)用的初始狀態(tài)休傍,可以作為 State 的默認值磨取。下面是一個實際的例子忙厌。

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着饥,作為加法的計算結(jié)果。其他運算的邏輯(比如減法)赁濒,也可以根據(jù) Action 的不同來實現(xiàn)挪拟。
實際應(yīng)用中玉组,Reducer 函數(shù)不用像上面這樣手動調(diào)用惯雳,store.dispatch方法會觸發(fā) Reducer 的自動執(zhí)行石景。為此潮孽,Store 需要知道 Reducer 函數(shù)往史,做法就是在生成 Store 的時候怠堪,將 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 呢庙洼?因為它可以作為數(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起愈。

3.7 純函數(shù)


Reducer 函數(shù)最重要的特征是抬虽,它是一個純函數(shù)阐污。也就是說功氨,只要是同樣的輸入,必定得到同樣的輸出弯菊。
純函數(shù)是函數(shù)式編程的概念管钳,必須遵守以下一些約束。

  • 不得改寫參數(shù)
  • 不能調(diào)用系統(tǒng) I/O 的API
  • 不能調(diào)用Date.now()或者Math.random()等不純的方法醇滥,因為每次會得到不一樣的結(jié)果

由于 Reducer 是純函數(shù)鸳玩,就可以保證同樣的State,必定得到同樣的 View米碰。但也正因為這一點虐译,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,唯一辦法就是生成一個新對象。這樣的好處是涵但,任何時候矮瘟,與某個 View 對應(yīng)的 State 總是一個不變的對象。

3.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 項目呼猪,就是組件的render方法或setState方法)放入listen宋距,就會實現(xiàn) View 的自動渲染。
store.subscribe方法返回一個函數(shù)壶唤,調(diào)用這個函數(shù)就可以解除監(jiān)聽闸盔。

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

unsubscribe();

四迎吵、Store 的實現(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ù)的默認初始值割岛。
下面是createStore方法的一個簡單實現(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ù)負責(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ù)負責(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ù)昌罩,每一個負責(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的簡單實現(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)

六歼郭、工作流程


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溺森,這時可以觸發(fā)重新渲染 View姥卢。

function listerner() {
  let newState = store.getState();
  component.setState(newState);   
}

七渣聚、實例:計數(shù)器


下面我們來看一個最簡單的實例症歇。

const Counter = ({ value }) => (
  <h1>{value}</h1>
);

const render = () => {
  ReactDOM.render(
    <Counter value={store.getState()}/>,
    document.getElementById('root')
  );
};

store.subscribe(render);
render();

上面是一個簡單的計數(shù)器,唯一的作用就是把參數(shù)value的值,顯示在網(wǎng)頁上。Store 的監(jiān)聽函數(shù)設(shè)置為render暮刃,每次 State 的變化都會導(dǎo)致網(wǎng)頁重新渲染。
下面加入一點變化步势,為Counter添加遞增和遞減的 Action破讨。

const Counter = ({ value }) => (
  <h1>{value}</h1>
  <button onClick={onIncrement}>+</button>
  <button onClick={onDecrement}>-</button>
);

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(
    <Counter
      value={store.getState()}
      onIncrement={() => store.dispatch({type: 'INCREMENT'})}
      onDecrement={() => store.dispatch({type: 'DECREMENT'})}
    />,
    document.getElementById('root')
  );
};

render();
store.subscribe(render);

完整的代碼請看這里隙笆。

總結(jié)一下:

  • Store
    Store 就是保存數(shù)據(jù)的地方撑柔,你可以把它看成一個容器瘸爽。整個應(yīng)用只能有一個 Store。
    Redux 提供createStore這個函數(shù)铅忿,用來生成 Store剪决。

  • State
    Store對象包含所有數(shù)據(jù)。如果想得到某個時點的數(shù)據(jù)檀训,就要對 Store 生成快照柑潦。這種時點的數(shù)據(jù)集合,就叫做 State峻凫。
    當(dāng)前時刻的 State渗鬼,可以通過store.getState()拿到。

  • Action
    State 的變化荧琼,會導(dǎo)致 View 的變化譬胎。但是,用戶接觸不到 State命锄,只能接觸到 View银择。所以,State 的變化必須是 View 導(dǎo)致的累舷。Action 就是 View 發(fā)出的通知浩考,表示 State 應(yīng)該要發(fā)生變化了。

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

  • Reducer
    Store 收到 Action 以后被盈,必須給出一個新的 State析孽,這樣 View 才會發(fā)生變化。這種 State 的計算過程就叫做 Reducer只怎。
    Reducer 是一個函數(shù)袜瞬,它接受 Action 和當(dāng)前 State 作為參數(shù),返回一個新的 State身堡。

  • store.subscribe()
    Store 允許使用store.subscribe方法設(shè)置監(jiān)聽函數(shù)邓尤,一旦 State 發(fā)生變化,就自動執(zhí)行這個函數(shù)贴谎。顯然汞扎,只要把 View 的更新函數(shù)(對于 React 項目,就是組件的render方法或setState方法)放入listen擅这,就會實現(xiàn) View 的自動渲染澈魄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市仲翎,隨后出現(xiàn)的幾起案子痹扇,更是在濱河造成了極大的恐慌铛漓,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲫构,死亡現(xiàn)場離奇詭異浓恶,居然都是意外死亡,警方通過查閱死者的電腦和手機结笨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門包晰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人禀梳,你說我怎么就攤上這事杜窄。” “怎么了算途?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵塞耕,是天一觀的道長。 經(jīng)常有香客問我嘴瓤,道長扫外,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任廓脆,我火速辦了婚禮筛谚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘停忿。我一直安慰自己驾讲,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布席赂。 她就那樣靜靜地躺著吮铭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪颅停。 梳的紋絲不亂的頭發(fā)上谓晌,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天,我揣著相機與錄音癞揉,去河邊找鬼纸肉。 笑死,一個胖子當(dāng)著我的面吹牛喊熟,可吹牛的內(nèi)容都是我干的柏肪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逊移,長吁一口氣:“原來是場噩夢啊……” “哼预吆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起胳泉,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤拐叉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扇商,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凤瘦,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年硝全,在試婚紗的時候發(fā)現(xiàn)自己被綠了泌霍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片士败。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖笔诵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姑子,我是刑警寧澤乎婿,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站街佑,受9級特大地震影響谢翎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沐旨,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一森逮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧磁携,春花似錦、人聲如沸谊迄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳞上。三九已至这吻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間篙议,已是汗流浹背唾糯。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鬼贱,地道東北人移怯。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像这难,于是被迫代替她去往敵國和親舟误。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 學(xué)習(xí)必備要點: 首先弄明白姻乓,Redux在使用React開發(fā)應(yīng)用時嵌溢,起到什么作用——狀態(tài)集中管理 弄清楚Redux是...
    賀賀v5閱讀 8,896評論 10 58
  • 前言 本文 有配套視頻眯牧,可以酌情觀看。 文中內(nèi)容因各人理解不同赖草,可能會有所偏差学少,歡迎朋友們聯(lián)系我討論。 文中所有內(nèi)...
    珍此良辰閱讀 11,904評論 23 111
  • 一秧骑、什么情況需要redux版确? 1、用戶的使用方式復(fù)雜 2乎折、不同身份的用戶有不同的使用方式(比如普通用戶和管...
    初晨的筆記閱讀 2,028評論 0 11
  • 看到這篇文章build an image gallery using redux saga绒疗,覺得寫的不錯,長短也適...
    smartphp閱讀 6,154評論 1 29
  • http://gaearon.github.io/redux/index.html 骂澄,文檔在 http://rac...
    jacobbubu閱讀 79,956評論 35 198