最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談對于react-thunk中間件的簡單理解

 更新時間:2019年05月01日 10:00:25   作者:freeze憤怒的菜鳥  
這篇文章主要介紹了淺談對于react-thunk中間件的簡單理解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

剛來公司的時候,對react項目中的thunk中間件的作用一直不太了解,最近有時間決定好好研究一下。鑒于本人初次寫博客,并已假設(shè)讀者已掌握redux的一些基本用法;如有錯誤,還望指出。不勝感激!

首先簡單回顧一下redux工作流程

圖畫的不太好,見諒;

對于reactUI組件來說,數(shù)據(jù)的來源無外乎兩種,一種是用戶主動觸發(fā)的動作,例如點擊事件、提交表單,輸入操作;另一種是組件主動的數(shù)據(jù)更新,如獲取頁面初始數(shù)據(jù),子組件接受父組件的props變化而進行更新視圖操作;

如圖所示,無論那種對于數(shù)據(jù)的操作,對于view都會派發(fā)出一個action

狀態(tài)的更新

正如我們所知,在redux里,每次更新后的Store都會對應(yīng)著一個新的view,而Store里面數(shù)據(jù)的更新依賴action的觸發(fā)————Store.dispatch(action)會自執(zhí)行初始化中createStore中注入的reducers,從而計算出新的狀態(tài)。

import { createStore } from 'redux'
//reducer 計算狀態(tài)的純函數(shù)
//initialState 初始化數(shù)據(jù)
//enhancers中間件
createStore(reducers, initialState, enhancers)

action的使用和插件的擴展

對于組件的輸入操作(如點擊事件),可以將store.dispatch(action)綁定到組件

 const store = createStore(reducer);
 const TodoList = ({ state, someActionCreator }) => (
   <ul>
    {state.map(someState =>
      <Todo
        key={someState.someData}
        onClick={() => store.dispatch(someActionCreator(state.someData))}
     />
    </ul>
    ) 

或者通過connect方法,從組件的props中拿到dispatch方法,發(fā)出一個action

 // 將state注入到組件的props里
 // 注意,這里的state指的是redux管理的數(shù)據(jù),每一個view的狀態(tài)對應(yīng)著
 //  唯一的state;
 //  state的集合就是redux管理的store
const mapStateToProps = store => ({
     state: store.state
})
​
 // 將action注入到組件的props 里
const mapDispatchToProps = dispatch => ({
 actions: state => dispatch(actionCreators(state))
})
​
export default connect(
 mapStateToProps,
 mapDispatchToProps
)(TodoList)

然后組件綁定事件就可以改成這樣 ,( actionCreators用于生成action, 參考官方鏈接 https://redux.js.org/basics/actions

 const TodoList = ({ state, actions }) => (
  `<ul>
    {state.map(someState =>
      <Todo
        key={someState.someData}
        onClick={() => actions(someState.someData)}
     />
    </ul>`
    ) 

那么問題來了,dispatch是同步執(zhí)行reducers生成新狀態(tài)的,對于頁面的操作沒有問題;但是如果點擊事件是請求了某個結(jié)果,需要等待結(jié)果響應(yīng)后再更新視圖呢?應(yīng)該如何處理?

因而redux引入了thunk中間件,對action進行了擴展

##thunk中間件解決了什么問題?

引入thunk插件后,我們可以在actionCreators內(nèi)部編寫邏輯,處理請求結(jié)果。而不只是單純的返回一個action對象。

//未引入前的寫法
let nextTodoId = 0
export const addTodo = text => ({
   type: 'ADD_TODO',
   id: nextTodoId++,
   text
 })
 
 //引入thunk后
 let nextTodoId = 0
 export const addTodo = text => ({
   return async dispatch => {
   //dosomething, request
   await request()
   dispatch({
   type: 'ADD_TODO',
   id: nextTodoId++,
   text
 })
   }
 })

thunk中間件的使用方法

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';

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

createStore其實可以接受三個參數(shù),第二個參數(shù)preloadedState一般作為整個應(yīng)用的初始化數(shù)據(jù),如果傳入了這個參數(shù),applyMiddleware就會被當做第三個參數(shù)處理

const store = createStore(
 reducer,
 initialState,
 applyMiddleware(thunk)
);

中間件都要放到applyMiddleware里,如果要添加中間件,可以依次添加,但是要遵循文檔定義的順序

const store = createStore(
 reducer,
 initialState,
 applyMiddleware(thunk,middleware1, middleware2)
);

源碼解讀

也許你會奇怪,為什么使用的時候要按照上面的寫法,那我們就一起看下方法的實現(xiàn)

首先是createStore的參數(shù)順序

function createStore(reducer, preloadedState, enhancer) {
 var _ref2;

 if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
  enhancer = preloadedState;
  preloadedState = undefined;
 }

 if (typeof enhancer !== 'undefined') {
  if (typeof enhancer !== 'function') {
   throw new Error('Expected the enhancer to be a function.');
  }

  return enhancer(createStore)(reducer, preloadedState);
 }

 if (typeof reducer !== 'function') {
  throw new Error('Expected the reducer to be a function.');
 }

第一個判斷已經(jīng)告訴了我們答案,參數(shù)的類型檢驗結(jié)果決定了順序

applyMiddleware是干什么用的
function applyMiddleware() {
 for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
  middlewares[_key] = arguments[_key];
 }

 return function (createStore) {
  return function () {
   for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
    args[_key2] = arguments[_key2];
   }

   var store = createStore.apply(undefined, args);
   var _dispatch = function dispatch() {
    throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.');
   };

   var middlewareAPI = {
    getState: store.getState,
    dispatch: function dispatch() {
     return _dispatch.apply(undefined, arguments);
    }
   };
   var chain = middlewares.map(function (middleware) {
    return middleware(middlewareAPI);
   });
   _dispatch = compose.apply(undefined, chain)(store.dispatch);

   return _extends({}, store, {
    dispatch: _dispatch
   });
  };
 };
}

代碼不多,而且非常清晰:

1、applyMiddleware顧名思義,用于調(diào)用各種中間件;
2、applyMiddleware執(zhí)行后,將所有入?yún)⒅虚g件存入一個數(shù)組,并且返回一個閉包(閉包的概念不做累述)
3、閉包接受一個createStore作為入?yún)⒉⑶覉?zhí)行后返回下一個閉包,createStore這個入?yún)⒂袥]有很眼熟,沒錯,就是redux的createStore。

返回結(jié)果

返回將所有中間件串聯(lián)存入的dispatch,執(zhí)行時從右向左執(zhí)行,第一次的執(zhí)行結(jié)果會返回給一下個,依次類推。

如何實現(xiàn)每個中間件串聯(lián)執(zhí)行

_dispatch = compose.apply(undefined, chain),使用了一個compose函數(shù),調(diào)用之后就可以將所有中間件串聯(lián)起來,那么compose又是如何實現(xiàn)的呢?

精華所在

function compose() {
 for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
  funcs[_key] = arguments[_key];
 }

 if (funcs.length === 0) {
  return function (arg) {
   return arg;
  };
 }

 if (funcs.length === 1) {
  return funcs[0];
 }

 return funcs.reduce(function (a, b) {
  return function () {
   return a(b.apply(undefined, arguments));
  };
 });
}

個人認為這個compose函數(shù)是整個redux中非常亮眼的部分,短短幾行代碼,就完成了一個核心功能的擴展,是責任鏈設(shè)計模式的經(jīng)典體現(xiàn)。

ALSO 我們也可以使用這個compose方法對applyMiddleware進行擴展

let devtools = () => noop => {
     console.log(noop);
     return noop;  //createStore
   };
const enhancers = [
  applyMiddleware(...middleware),
  devtools()
 ];
createStore(reducers, initialState, compose(...enhancers));

然后回來,我們就明白了createStore中的設(shè)計

//如果存在中間件參數(shù),那么將會得到一個經(jīng)過改裝的dispatch
// return _extends({}, store, {dispatch: _dispatch});
if (typeof enhancer !== 'undefined') {
  if (typeof enhancer !== 'function') {
   throw new Error('Expected the enhancer to be a function.');
  }

  return enhancer(createStore)(reducer, preloadedState);
 }

dispatch經(jīng)過了怎樣的改裝

如上已經(jīng)說過,compose會將傳入的函數(shù)數(shù)組從右向左串聯(lián)執(zhí)行

compose.apply(undefined, chain)(store.dispatch);

thunk一定會接受上一個中間件的執(zhí)行結(jié)果繼續(xù)執(zhí)行,然后最終在createState里返回一個改造好的dispatch, 接下來我只要看下thunk是怎樣實現(xiàn)的,就了解了整個中間件使用的原理:

function createThunkMiddleware(extraArgument) {
 return function (_ref) {
  var dispatch = _ref.dispatch,
    getState = _ref.getState;
  return function (next) {
     //最終的dispatch
     //next就是接收的store.dispatch參數(shù),為上一個中間件改造過的dispatch
   return function (action) {
    if (typeof action === 'function') {
     return action(dispatch, getState, extraArgument);
    }

    return next(action);
   };
  };
 };
}

var thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

代碼同樣精煉,改造后的dispatch入?yún)⒔邮艿臄?shù)據(jù)類型:

1、非function,不處理,將action 傳給下一個中間件,最終都會根據(jù)傳入的action計算相應(yīng)的reducers(開頭說的自執(zhí)行)————store.dispatch(action)
2、function類型的action, 自動觸發(fā)函數(shù),并且將store.dispatch傳入

總結(jié)

再結(jié)合開始介紹的thunk用法,我們就明白了thunk的原理,可以在actionCreators里通過返回一個函數(shù),然后就可以在函數(shù)里編寫某些異步操作了,待異步操作結(jié)束,最后通過傳入的store.dispatch,發(fā)出action通知給Store要進行狀態(tài)更新。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • react 路由跳轉(zhuǎn)的7種方式實現(xiàn)

    react 路由跳轉(zhuǎn)的7種方式實現(xiàn)

    本文介紹了React中六種常見的路由跳轉(zhuǎn)方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-03-03
  • 在React頁面重新加載時保留數(shù)據(jù)的實現(xiàn)方法總結(jié)

    在React頁面重新加載時保留數(shù)據(jù)的實現(xiàn)方法總結(jié)

    在React頁面重新加載時保留數(shù)據(jù),可以通過多種方法來實現(xiàn),常見的方法包括使用瀏覽器的本地存儲(Local Storage 或 Session Storage)、URL參數(shù)、以及服務(wù)器端存儲等,本文給大家總結(jié)了一些具體實現(xiàn)方法,需要的朋友可以參考下
    2024-06-06
  • React服務(wù)端渲染(總結(jié))

    React服務(wù)端渲染(總結(jié))

    當我們要求渲染時間盡量快、頁面響應(yīng)速度快時就會用到服務(wù)端渲染,本篇文章主要介紹了React服務(wù)端渲染,有興趣的可以了解一下
    2017-07-07
  • React三大屬性之Refs的使用詳解

    React三大屬性之Refs的使用詳解

    這篇文章主要介紹了React三大屬性之Refs的使用詳解,幫助大家更好的理解和學習使用React,感興趣的朋友可以了解下
    2021-04-04
  • React Native自定義標題欄組件的實現(xiàn)方法

    React Native自定義標題欄組件的實現(xiàn)方法

    今天講一下如何實現(xiàn)自定義標題欄組件,我們都知道RN有一個優(yōu)點就是可以組件化,在需要使用該組件的地方直接引用并傳遞一些參數(shù)就可以了,這種方式確實提高了開發(fā)效率。對React Native自定義標題欄組件的實現(xiàn)方法感興趣的朋友參考下
    2017-01-01
  • react+tsx中使用better-scroll詳解

    react+tsx中使用better-scroll詳解

    這篇文章主要介紹了react+tsx中使用better-scroll,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • React和Vue的props驗證示例詳解

    React和Vue的props驗證示例詳解

    這篇文章主要介紹了React和Vue的props驗證,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • 詳解在React項目中安裝并使用Less(用法總結(jié))

    詳解在React項目中安裝并使用Less(用法總結(jié))

    這篇文章主要介紹了詳解在React項目中安裝并使用Less(用法總結(jié)),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • React.memo函數(shù)中的參數(shù)示例詳解

    React.memo函數(shù)中的參數(shù)示例詳解

    這篇文章主要為大家介紹了React.memo函數(shù)中的參數(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • React Native 資源包拆分實戰(zhàn)分析

    React Native 資源包拆分實戰(zhàn)分析

    這篇文章主要為大家介紹了React Native 資源包拆分實戰(zhàn)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08

最新評論

海林市| 平原县| 蒲城县| 瓦房店市| 华宁县| 丹阳市| 淳安县| 河西区| 南充市| 怀远县| 北流市| 连云港市| 本溪| 读书| 通河县| 奉化市| 福建省| 平利县| 中宁县| 华安县| 安新县| 长宁区| 板桥市| 惠水县| 曲阳县| 水城县| 湖北省| 临猗县| 石嘴山市| 湛江市| 五寨县| 九龙县| 双桥区| 墨江| 安远县| 含山县| 台湾省| 松原市| 宁津县| 武鸣县| 怀柔区|