Redux, redux-saga

從數(shù)據(jù)到界面響應流程
用戶在界面上操作扇调,發(fā)起action把兔,action在reducer中改變store上的數(shù)據(jù)玉锌,或者在saga中調(diào)接口改變數(shù)據(jù)名挥,促使頁面刷新

1.ManagementConsole項目執(zhí)行npm run dev

image.png

解決:先執(zhí)行npm run build-libs-dev

  1. 交互流程:

① Index.tsx -> action ->reducer ->store(app.tsx)

② Index.tsx -> action ->saga -> reducer ->store(app.tsx)

Reducer :(state,action)=>newstate

(以 作業(yè)中心 -> 布置作業(yè) ->個人草稿 初始化界面數(shù)據(jù)的獲取為例 )頁面加載出來觸發(fā)數(shù)據(jù)的獲取

③ 首先在 個人草稿 對應的頁面組件中觸發(fā)action的地方

image.png

④ 開始找action

image.png

⑤ Saga

image.png

⑥ 返回到action

image.png

⑦ 進入reducer(在此返回saga請求所得數(shù)據(jù)給頁面組件)

image.png
  1. 以 作業(yè)中心 -> 布置作業(yè) ->個人草稿 刪除某個記錄為例

① 頁面觸發(fā)action

image.png

② action

image.png

③ saga

image.png

④ action

image.png

⑤ reducer

image.png
  1. connect方法接受兩個參數(shù): State和Dispatch。它們定義了 UI 組件的業(yè)務邏輯主守。前者負責輸入邏輯禀倔,即將state映射到 UI 組件的參數(shù)(props),后者負責輸出邏輯参淫,即將用戶對 UI 組件的操作映射成 Action救湖。
image.png

注意:對于其中的editDate: editDateSelector(state),有兩種寫法(冒號左邊的editDate代表UI組件同名的參數(shù),右邊的editDateSelector是一個函數(shù) 可以從state算出editDate的值):

① editDate: editDateSelector(state)涎才,通過selector

image.png

② 跳過selector

editDate: state.getEditDataReducer.getEditData,
image.png

注意:拿getRequestEidtData鍵值對進行說明

冒號左邊的是UI組件對應的同名參數(shù)鞋既,右邊的函數(shù)定義了UI組件的參數(shù)怎樣發(fā)出Action

額外理解

1. 在入口文件app.tsx中引入了react-hot-loader中的AppContainer組件,這個組件下的所有子組件都會在發(fā)生變化時觸發(fā)熱更新

image.png

2.<AppContainer />是一個處理reloading的組件耍铜,它同樣會處理錯誤邑闺。Root組件必須嵌套在AppContainer里面作為子組件,當在生產(chǎn)模式的時候,AppContainer會自動禁用,只是簡單的返回子組件

  1. Store

Store 就是保存數(shù)據(jù)的地方玉掸,可以把它看成一個容器,整個應用只能有一個 Store。Redux 提供createStore這個函數(shù)來生成 Store蹭沛。

image.png

上面代碼中,createStore函數(shù)接受另一個函數(shù)作為參數(shù)章鲤,返回新生成的 Store 對象摊灭。在生成 Store 的時候,將 Reducer 傳入createStore方法dispatch方法會觸發(fā) Reducer 的自動執(zhí)行

const store = createStore(
    createReducer(undefined),
    composeEnhancers( applyMiddleware(sagaMiddleware, reduxRouterMiddleware))
);

  1. State

Store對象包含所有數(shù)據(jù)败徊。如果想得到某個時點的數(shù)據(jù)帚呼,就要對 Store 生成快照。這種時點的數(shù)據(jù)集合,就叫做 State煤杀。當前時刻的 State眷蜈,可以通過store.getState()拿到。

  1. Action

State 的變化沈自,會導致 View 的變化酌儒。但是,用戶接觸不到 State枯途,只能接觸到 View忌怎。所以,State 的變化必須是 View 導致的酪夷。Action 就是 View 發(fā)出的通知榴啸,表示 State 應該要發(fā)生變化了。改變 State 的唯一辦法晚岭,就是使用 Action鸥印。它會運送數(shù)據(jù)到 Store。

  1. Dispatch

dispatch()是 View 發(fā)出 Action 的唯一方法坦报,dispatch接受一個 Action 對象作為參數(shù)库说,將它發(fā)送出去

  1. Reducer

Store 收到 Action 以后,必須給出一個新的 State片择,這樣 View 才會發(fā)生變化璃弄。這種 State 的計算過程(邏輯處理)就叫做 Reducer。Reducer 是一個函數(shù)构回,它接受 Action 和當前 State 作為參數(shù),返回一個新的 State疏咐。

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

[DRAFT_INIT_SUCCEEDED]: (state, action: Action<any>) => {
    return Object.assign({},state,{
        initDraftData: action.payload
    });
},

總reducer

image.png

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

  1. redux-thunk 中間件

Action 是由store.dispatch方法發(fā)送的浑塞。而store.dispatch方法正常情況下借跪,參數(shù)只能是對象,不能是函數(shù)酌壕。這時掏愁,就要使用中間件redux-thunk。

import reducer from './reducers';

// Note: this API requires redux@>=3.1.0
const store = createStore(
  reducer,
  applyMiddleware(thunk)
);

上面代碼使用redux-thunk中間件卵牍,改造store.dispatch果港,使得store.dispatch可以接受函數(shù)作為參數(shù)。

因此糊昙,異步操作的第一種解決方案就是辛掠,寫出一個返回函數(shù)的 Action Creator,然后使用redux-thunk中間件改造store.dispatch。(在線教育使用的就是該方案)

  1. redux-promise 中間件

既然 Action Creator 可以返回函數(shù)萝衩,當然也可以返回其他值回挽。另一種異步操作的解決方案,就是讓 Action Creator 返回一個 Promise 對象猩谊。

這就需要使用redux-promise中間件千劈。

import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise';
import reducer from './reducers';

const store = createStore(
  reducer,
  applyMiddleware(promiseMiddleware)
); 

這個中間件使得store.dispatch方法可以接受 Promise 對象作為參數(shù)。這時牌捷,Action Creator 有兩種寫法墙牌。寫法一,返回值是一個 Promise 對象宜鸯。

const fetchPosts = 
  (dispatch, postTitle) => new Promise(function (resolve, reject) {
     dispatch(requestPosts(postTitle));
     return fetch(`/some/API/${postTitle}.json`)
       .then(response => {
         type: 'FETCH_POSTS',
         payload: response.json()
       });
});

寫法二憔古,Action 對象的payload屬性是一個 Promise 對象。這需要從redux-actions模塊引入createAction方法淋袖,并且寫法也要變成下面這樣鸿市。

import { createAction } from 'redux-actions';

class AsyncApp extends Component {
  componentDidMount() {
    const { dispatch, selectedPost } = this.props
    // 發(fā)出同步 Action
    dispatch(requestPosts(selectedPost));
    // 發(fā)出異步 Action
    dispatch(createAction(
      'FETCH_POSTS', 
      fetch(`/some/API/${postTitle}.json`)
        .then(response => response.json())
    ));
  }

上面代碼中,第二個dispatch方法發(fā)出的是異步 Action即碗,只有等到操作結束焰情,這個 Action 才會實際發(fā)出。注意剥懒,createAction的第二個參數(shù)必須是一個 Promise 對象内舟。

  1. React-Redux

React-Redux 將所有組件分成兩大類:UI 組件(presentational component)和容器組件(container component)初橘。UI 組件負責 UI 的呈現(xiàn)验游,容器組件負責管理數(shù)據(jù)和邏輯。

如果一個組件既有 UI 又有業(yè)務邏輯保檐,那怎么辦耕蝉?回答是,將它拆分成下面的結構:外面是一個容器組件夜只,里面包了一個UI 組件垒在。前者負責與外部的通信,將數(shù)據(jù)傳給后者扔亥,由后者渲染出視圖场躯。

React-Redux 規(guī)定,所有的 UI 組件都由用戶提供旅挤,容器組件則是由 React-Redux 自動生成踢关。也就是說,用戶負責視覺層粘茄,狀態(tài)管理則是全部交給它耘成。

  1. UI 組件

UI 組件有以下幾個特征

§ 只負責 UI 的呈現(xiàn),不帶有任何業(yè)務邏輯

§ 沒有狀態(tài)(即不使用this.state這個變量)

§ 所有數(shù)據(jù)都由參數(shù)(this.props)提供

§ 不使用任何 Redux 的 API

因為不含有狀態(tài),UI 組件又稱為"純組件"瘪菌,即它純函數(shù)一樣撒会,純粹由參數(shù)決定它的值。

  1. 容器組件

容器組件的特征恰恰相反师妙。

§ 負責管理數(shù)據(jù)和業(yè)務邏輯诵肛,不負責 UI 的呈現(xiàn)

§ 帶有內(nèi)部狀態(tài)

§ 使用 Redux 的 API

  1. connect()

React-Redux 提供connect方法,用于從 UI 組件生成容器組件默穴。connect的意思怔檩,就是將這兩種組件連起來

import { connect } from 'react-redux'
const VisibleTodoList = connect()(TodoList);

上面代碼中,TodoList是 UI 組件蓄诽,VisibleTodoList就是由 React-Redux 通過connect方法自動生成的容器組件薛训。

但是,因為沒有定義業(yè)務邏輯仑氛,上面這個容器組件毫無意義乙埃,只是 UI 組件的一個單純的包裝層。為了定義業(yè)務邏輯锯岖,需要給出下面兩方面的信息:

(1)輸入邏輯:外部的數(shù)據(jù)(即state對象)如何轉換為 UI 組件的參數(shù)

(2)輸出邏輯:用戶發(fā)出的動作如何變?yōu)?Action 對象介袜,從 UI 組件傳出去

因此,connect方法的完整 API 如下出吹。

import { connect } from 'react-redux'

const VisibleTodoList = connect(
  mapStateToProps,      //connect第一個參數(shù)遇伞,是一個函數(shù) 執(zhí)行后返回一個對象
  mapDispatchToProps  //第二個參數(shù),可以是一個函數(shù)或對象執(zhí)行后返回一個對象
)(TodoList)

上面代碼中捶牢,connect方法接受兩個參數(shù):mapStateToProps和mapDispatchToProps鸠珠。它們定義了 UI 組件的業(yè)務邏輯。前者負責輸入邏輯秋麸,即將state映射到 UI 組件的參數(shù)(props)跳芳,后者負責輸出邏輯,即將用戶對 UI 組件的操作映射成 Action竹勉。

  1. mapStateToProps()

mapStateToProps是一個函數(shù)。它的作用就是像它的名字那樣娄琉,建立一個從(外部的)state對象到(UI 組件的)props對象的映射關系次乓。

作為函數(shù),mapStateToProps執(zhí)行后應該返回一個對象孽水,里面的每一個鍵值對就是一個映射票腰。請看下面的例子。

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

上面代碼中女气,mapStateToProps是一個函數(shù)杏慰,它接受state作為參數(shù),返回一個對象。這個對象有一個todos屬性缘滥,代表 UI 組件的同名參數(shù)轰胁,后面的getVisibleTodos也是一個函數(shù),可以從state算出 todos 的值朝扼。

下面就是getVisibleTodos的一個例子赃阀,用來算出todos。

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    default:
      throw new Error('Unknown filter: ' + filter)
  }
}

mapStateToProps會訂閱 Store擎颖,每當state更新的時候榛斯,就會自動執(zhí)行,重新計算 UI 組件的參數(shù)搂捧,從而觸發(fā) UI 組件的重新渲染驮俗。

mapStateToProps的第一個參數(shù)總是state對象,還可以使用第二個參數(shù)允跑,代表容器組件的props對象

// 容器組件的代碼
//    <FilterLink filter="SHOW_ALL">
//      All
//    </FilterLink>

const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.filter === state.visibilityFilter
  }
}

使用ownProps作為參數(shù)后王凑,如果容器組件的參數(shù)發(fā)生變化,也會引發(fā) UI 組件重新渲染吮蛹。

connect方法可以省略mapStateToProps參數(shù)荤崇,那樣的話,UI 組件就不會訂閱Store潮针,就是說 Store 的更新不會引起 UI 組件的更新

  1. mapDispatchToProps()

mapDispatchToProps是connect函數(shù)的第二個參數(shù)术荤,用來建立 UI 組件的參數(shù)到store.dispatch方法的映射。也就是說每篷,它定義了哪些用戶的操作應該當作 Action瓣戚,傳給 Store。它可以是一個函數(shù)焦读,也可以是一個對象子库。

如果mapDispatchToProps是一個函數(shù),會得到dispatch和ownProps(容器組件的props對象)兩個參數(shù)矗晃。

const mapDispatchToProps = (
  dispatch,
  ownProps
) => {
  return {
    onClick: () => {
      dispatch({
        type: 'SET_VISIBILITY_FILTER',
        filter: ownProps.filter
      });
    }
  };
}

從上面代碼可以看到仑嗅,mapDispatchToProps作為函數(shù)應該返回一個對象,該對象的每個鍵值對都是一個映射张症,定義了UI組件的參數(shù)怎樣發(fā)出Action

如果mapDispatchToProps是一個對象仓技,它的每個鍵名也是對應 UI 組件的同名參數(shù),鍵值應該是一個函數(shù)俗他,會被當作 Action creator 脖捻,返回的 Action 會由 Redux 自動發(fā)出。舉例來說兆衅,上面的mapDispatchToProps寫成對象就是下面這樣

const mapDispatchToProps = {
  onClick: (filter) => {
    type: 'SET_VISIBILITY_FILTER',
    filter: filter
  };
}
  1. <Provider> 組件

Connect方法生成容器組件后地沮,需要讓容器組件拿到state對象才能生成UI組件的參數(shù)

一種解決方法是將state對象作為參數(shù)傳入容器組件嗜浮,但是這樣做比較麻煩,尤其是容器組件可能在很深的層級摩疑,一級級將state傳下去將很麻煩

React-Redux提供Provider組件危融,可以讓容器拿到state (可以結合TeacherClient項目理解)

import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp);

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

上面代碼中,Provider在根組件外面包了一層未荒,這樣一來专挪,App的所有子組件就默認都可以拿到state了

關于調(diào)用后端接口

接口的調(diào)用都是需要access_token的,財聯(lián)邦的是在接口url后拼access_token和sessionId片排,芝士網(wǎng)是傳authorization

有關Token(authorization—--接口調(diào)用需要的參數(shù))

(以CourseManagement工程為例)

  1. image.png

    中寨腔,先主動判斷authorization是否有值,有就請求request()正常加載頭部的Tab率寡,沒有值就請求requestToken((window as GlobalDefinitions).user)獲取

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
  1. 有了authorization迫卢,也就是用戶登錄了,工程中的接口就可以調(diào)用了(以獲取學生信息為例)
image.png
image.png
image.png
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冶共,一起剝皮案震驚了整個濱河市乾蛤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捅僵,老刑警劉巖家卖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異庙楚,居然都是意外死亡上荡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門馒闷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酪捡,“玉大人,你說我怎么就攤上這事纳账」滢保” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵疏虫,是天一觀的道長永罚。 經(jīng)常有香客問我,道長卧秘,這世上最難降的妖魔是什么呢袱? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮斯议,結果婚禮上,老公的妹妹穿的比我還像新娘醇锚。我一直安慰自己哼御,他們只是感情好坯临,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著恋昼,像睡著了一般看靠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上液肌,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天挟炬,我揣著相機與錄音,去河邊找鬼嗦哆。 笑死谤祖,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的老速。 我是一名探鬼主播粥喜,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼橘券!你這毒婦竟也來了额湘?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤旁舰,失蹤者是張志新(化名)和其女友劉穎锋华,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箭窜,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡毯焕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绽快。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芥丧。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖坊罢,靈堂內(nèi)的尸體忽然破棺而出续担,到底是詐尸還是另有隱情,我是刑警寧澤活孩,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布物遇,位于F島的核電站,受9級特大地震影響憾儒,放射性物質(zhì)發(fā)生泄漏询兴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一起趾、第九天 我趴在偏房一處隱蔽的房頂上張望诗舰。 院中可真熱鬧,春花似錦训裆、人聲如沸眶根。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽属百。三九已至记劝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間族扰,已是汗流浹背厌丑。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留渔呵,地道東北人怒竿。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像厘肮,于是被迫代替她去往敵國和親愧口。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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

  • 一类茂、什么情況需要redux耍属? 1、用戶的使用方式復雜 2巩检、不同身份的用戶有不同的使用方式(比如普通用戶和管...
    初晨的筆記閱讀 2,013評論 0 11
  • 做React需要會什么兢哭? react的功能其實很單一领舰,主要負責渲染的功能,現(xiàn)有的框架迟螺,比如angular是一個大而...
    蒼都閱讀 14,740評論 1 139
  • 技術棧: react + redux + webpack + react-router + ES6/7/8 + i...
    黃昏少年閱讀 3,075評論 0 19
  • 學習必備要點: 首先弄明白冲秽,Redux在使用React開發(fā)應用時,起到什么作用——狀態(tài)集中管理 弄清楚Redux是...
    賀賀v5閱讀 8,877評論 10 58
  • 前言 本文 有配套視頻矩父,可以酌情觀看锉桑。 文中內(nèi)容因各人理解不同,可能會有所偏差窍株,歡迎朋友們聯(lián)系我討論民轴。 文中所有內(nèi)...
    珍此良辰閱讀 11,894評論 23 111