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

React?redux?原理及使用詳解

 更新時(shí)間:2022年11月28日 14:29:26   作者:空山與新雨  
這篇文章主要為大家介紹了React?redux?原理及使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

概述

  • 一個(gè)狀態(tài)管理工具
  • Store:保存數(shù)據(jù)的地方,你可以把它看成一個(gè)容器,整個(gè)應(yīng)用只能有一個(gè) Store。
  • State:包含所有數(shù)據(jù),如果想得到某個(gè)時(shí)點(diǎn)的數(shù)據(jù),就要對 Store 生成快照,這種時(shí)點(diǎn)的數(shù)據(jù)集合,就叫做 State。
  • Action:Action 就是 View 發(fā)出的通知,表示 State 應(yīng)該要發(fā)生變化了。
  • Action Creator:View 要發(fā)送多少種消息,就會有多少種 Action。如果都手寫,會很麻煩,所以我們定義一個(gè)函數(shù)來生成 Action,這個(gè)函數(shù)就叫 Action Creator。
  • Reducer:Store 收到 Action 以后,必須給出一個(gè)新的 State。這種 State 的計(jì)算過程就叫做 Reducer。Reducer 是一個(gè)函數(shù),它接受 Action 和當(dāng)前 State 作為參數(shù),返回一個(gè)新的 State。
  • dispatch:是 View 發(fā)出 Action 的唯一方法。

整個(gè)工作流程:

  • 首先,用戶(通過 View)發(fā)出 Action,發(fā)出方式就用到了 dispatch 方法。
  • 然后,Store 自動調(diào)用 Reducer,并且傳入兩個(gè)參數(shù):當(dāng)前 State 和收到的 Action,Reducer 會返回新的 State
  • State 一旦有變化,Store 就會調(diào)用監(jiān)聽函數(shù),來更新 View。

三大原則

1.單一數(shù)據(jù)源(Store) 整個(gè)應(yīng)用的State被存放在一棵Object tree中,并且這個(gè)Object tree只存在唯一一個(gè)Store中;

2.State是只讀的 唯一改變 State 的方法就是觸發(fā) Action,Action 是一個(gè)用于描述已發(fā)生事件的普通對象。 確保了所有的修改都能被集中化處理。

3.通過純函數(shù)Reducer來修改Store, Reducer 只是一些純函數(shù),它接收先前的 State 和 Action,并返回新的 State。 即reducer(state, action) => new state

createStore創(chuàng)建store

  • createStore 方法接受 3 個(gè)參數(shù)參數(shù) (reducer, [preloadedState], enhancer);
    返回 store,store 上掛載著 dispatch、getState、subscribe、replaceReducer 等方法
  • 第二個(gè)參數(shù)是 preloadedState,它是 state 的初始值,實(shí)際上他并不僅僅是扮演著一個(gè) initialState 的角色,如果我們第二個(gè)參數(shù)是函數(shù)類型,createStore 會認(rèn)為傳入了一個(gè) enhancer,如果我們傳入了一個(gè) enhancer,createStore 會返回 enhancer(createStore)(reducer, preloadedState)的調(diào)用結(jié)果,這是常見高階函數(shù)的調(diào)用方式。
  • enhancer 接受 createStore 作為參數(shù),對 createStore 的能力進(jìn)行增強(qiáng),并返回增強(qiáng)后的 createStore。然后再將 reducer 和 preloadedState 作為參數(shù)傳給增強(qiáng)后的 createStore,最終得到生成的 store。
export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    // 第二個(gè)參數(shù)是一個(gè)函數(shù),沒有第三個(gè)參數(shù)的情況
    enhancer = preloadedState;
    preloadedState = undefined;
  }
  // 如果第三個(gè)參數(shù)是函數(shù)走下面的邏輯,返回一個(gè)新的createStore
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      // enhancer 不是函數(shù)就報(bào)錯(cuò)
      throw new Error('Expected the enhancer to be a function.');
    }
    // enhancer就是高階函數(shù),強(qiáng)化了本身這個(gè)createStore的函數(shù),拿到增強(qiáng)后的createStore函數(shù)去處理
    // applyMiddleware這個(gè)函數(shù)還會涉及到這個(gè)
    return enhancer(createStore)(reducer, preloadedState);
  }
  if (typeof reducer !== 'function') {
    // reducer不是函數(shù)報(bào)錯(cuò)
    throw new Error('Expected the reducer to be a function.');
  }
  // 其他代碼省略
  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable,
  };
}

applyMiddleware 應(yīng)用中間件

  • 返回一個(gè)函數(shù) enhancer;
  • 右邊中間件的執(zhí)行時(shí)機(jī)由左邊的中間件決定,這是因?yàn)?next 的方法的調(diào)用時(shí)機(jī)由右邊控制
  • dispatch 的處理使用了閉包,這樣保證在中間件中調(diào)用 dispatch 也是用的最終的 dispatch,也是同一個(gè) dispatch;
  • 寫中間件的時(shí)候如果要調(diào)用 dispatch,一定要有跳出條件,防止死循環(huán)
export default function applyMiddleware(...middlewares) {
  return (createStore) =>
    (...args) => {
      const store = createStore(...args);
      let dispatch = () => {
        throw new Error(
          'Dispatching while constructing your middleware is not allowed. ' +
            'Other middleware would not be applied to this dispatch.',
        );
      };
      const middlewareAPI = {
        getState: store.getState,
        dispatch: (...args) => dispatch(...args),
      };
      const chain = middlewares.map((middleware) => middleware(middlewareAPI));
      dispatch = compose(...chain)(store.dispatch);
      return {
        ...store,
        dispatch,
      };
    };
}
// 其實(shí)就是修改了dispatch
let store = applyMiddleware(middleware1,middleware2)(createStore)(rootReducer);

combineReducers 合并多個(gè)reducer

從執(zhí)行結(jié)果看,這時(shí)候 state 已經(jīng)變成了一個(gè)以這些 reducer 為 key 的對象;

reducer 也變成了一個(gè)合并的 reducer;

遍歷執(zhí)行所有的 reducer 的時(shí)候把 action 傳進(jìn)去,返回新的 state;

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers);
  const finalReducers = {};
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i];
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key];
    }
  }
  const finalReducerKeys = Object.keys(finalReducers);
  /* 返回一個(gè)整合后的reducers */
  return function combination(state = {}, action) {
    let hasChanged = false;
    const nextState = {};
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i];
      const reducer = finalReducers[key];
      const previousStateForKey = state[key];
      const nextStateForKey = reducer(previousStateForKey, action);
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action);
        throw new Error(errorMessage);
      }
      nextState[key] = nextStateForKey;
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
    }
    return hasChanged ? nextState : state;
  };
}

dispatch

  • 默認(rèn)的 action 只能是普通對象,除非使用了第三方中間件,比如 redux-thunk
function dispatch(action) {
  if (!isPlainObject(action)) {
    throw new Error(
      'Actions must be plain objects. ' +
        'Use custom middleware for async actions.',
    );
  }
  if (typeof action.type === 'undefined') {
    throw new Error(
      'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?',
    );
  }
  if (isDispatching) {
    throw new Error('Reducers may not dispatch actions.');
  }
  try {
    isDispatching = true;
    currentState = currentReducer(currentState, action);
  } finally {
    isDispatching = false;
  }
  var listeners = (currentListeners = nextListeners);
  for (var i = 0; i < listeners.length; i++) {
    var listener = listeners[i];
    listener();
  }
  return action;
}

中間件

  • Redux 中間件在發(fā)起一個(gè) action 至 action 到達(dá) reducer 的之間提供了一個(gè)第三方的擴(kuò)展。本質(zhì)上通過插件的形式,將原本的 action->redux 的流程改變?yōu)?action->middleware1->middleware2-> ... ->reducer,通過改變數(shù)據(jù)流,從而實(shí)現(xiàn)例如異步 Action、日志輸入的功能。
  • Redux 中間件范式
    • 一個(gè)中間件接收 store 作為參數(shù),會返回一個(gè)函數(shù)
    • 返回的這個(gè)函數(shù)接收老的 dispatch 函數(shù)作為參數(shù)(一般用 next 作為形參),會返回一個(gè)新的函數(shù)
    • 返回的新函數(shù)就是新的 dispatch 函數(shù),這個(gè)函數(shù)里面可以拿到外面兩層傳進(jìn)來的 store 和老 dispatch 函數(shù)
function logger(store) {
  return function (next) {
    return function (action) { // 新的 dispatch 函數(shù)
      console.group(action.type);
      console.info('dispatching', action);
      let result = next(action);
      console.log('next state', store.getState());
      console.groupEnd();
      return result;
    };
  };
}

中間件的調(diào)用順序

  • 首先調(diào)用順序和書寫順序是一致的,但是這里面的洋蔥模型包含了兩次順序,從洋蔥出來的順序是和書寫順序相反
import React from 'react';
import { createStore, applyMiddleware } from 'redux';
function createLogger({ getState, dispatch }) {
  return (next) => (action) => {
    const prevState = getState();
    console.log('createLogger1');
    const returnValue = next(action);
    const nextState = getState();
    const actionType = String(action.type);
    const message = `action ${actionType}`;
    console.log(`%c prev state`, `color: #9E9E9E`, prevState);
    console.log(`%c action`, `color: #03A9F4`, action);
    console.log(`%c next state`, `color: #4CAF50`, nextState);
    return returnValue;
  };
}
function createLogger2({ getState }) {
  return (next) => (action) => {
    const console = window.console;
    const prevState = getState();
    console.log('createLogger2');
    const returnValue = next(action);
    const nextState = getState();
    const actionType = String(action.type);
    const message = `action ${actionType}`;
    console.log(`%c prev state2`, `color: #9E9E9E`, prevState);
    console.log(`%c action2`, `color: #03A9F4`, action);
    console.log(`%c next state2`, `color: #4CAF50`, nextState);
    return returnValue;
  };
}
const reducer = function (state = { number: 0 }, action) {
  switch (action.type) {
    case 'add':
      return {
        number: state.number + action.number,
      };
    default:
      return state;
  }
};
const store = createStore(
  reducer,
  applyMiddleware(createLogger, createLogger2),
);
store.subscribe(function () {
  console.log(1111);
});
const { dispatch } = store;
const App = () => {
  const handler = () => {
    dispatch({ type: 'add', number: 10 });
  };
  return (
    <div>
      <button onClick={handler}>觸發(fā)redux</button>
    </div>
  );
};
export default App;

store

store 的屬性如下:

dispatch: ƒ dispatch(action)

getState: ƒ getState()

replaceReducer: ƒ replaceReducer(nextReducer)

subscribe: ƒ subscribe(listener)

redux 數(shù)據(jù)流

Redux 的數(shù)據(jù)流是這樣的:

界面 => action => reducer => store => react => virtual dom => 界面

bindActionCreators

將action對象轉(zhuǎn)為一個(gè)帶dispatch的方法

比如connect接收的mapDispatchToProps 是對象,會使用 bindActionCreators 處理; 接收 actionCreator 和 dispatch,返回一個(gè)函數(shù);

function bindActionCreator(actionCreator, dispatch) {
  // 返回一個(gè)函數(shù)
  return function() {
    return dispatch(actionCreator.apply(this, arguments))
  }
}
function bindActionCreators(actionCreators, dispatch) {
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }
  const boundActionCreators = {}
  for (const key in actionCreators) {
    const actionCreator = actionCreators[key]
    if (typeof actionCreator === 'function') {
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    }
  }
  return boundActionCreators
}
const mapDispatchToProps = {  // actionCreators 這是個(gè)集合,
  onClick: (filter) => {
    type: 'SET_VISIBILITY_FILTER',
      filter: filter
  };
}
轉(zhuǎn)換為:
const mapDispatchToProps = {  // actionCreators 這是個(gè)集合,
  onClick:function(filter) {
    return dispatch({  // dispatch 是閉包中的方法
      type: 'SET_VISIBILITY_FILTER',
      filter: filter
    })
  }
}

compose

函數(shù)套函數(shù),compose(...chain)(store.dispatch)結(jié)果返回一個(gè)加強(qiáng)了的 dispatch;

這點(diǎn)和koa比較相似,這個(gè) dispatch 在執(zhí)行的時(shí)候會調(diào)用中間件。

function compose(...funcs) {
  if (funcs.length === 0) {
    return (arg) => arg;
  }
  if (funcs.length === 1) {
    return funcs[0];
  }
  // 每一次reduce迭代都會返回一個(gè)加強(qiáng)版的dispatch
  return funcs.reduce(
    (a, b) =>
      (...args) =>
        a(b(...args)),
  );
}

加強(qiáng)版 dispatch(一個(gè)方法,接收 action 參數(shù)),在中間件中用 next 表示,執(zhí)行 next 之后,會形成一個(gè)鏈條。

enhancer

  • enhancer,翻譯過來就是 store 加強(qiáng)器,比如 applymiddleware 的返回值就是一個(gè) enhaner。store 加強(qiáng)器可以重新構(gòu)建一個(gè)更強(qiáng)大的 store,來替換之前的基礎(chǔ)版的 store,讓你的程序可以增加很多別的功能,比如 appllymiddleware 可以給你的 redux 增加中間件,使之可以擁有異步功能,日志功能等!
// 以createStore為參數(shù)
(createStore) =>
  (...args) => {};

使用 redux 常遇見的問題

  • 樣板代碼過多 增加一個(gè) action 往往需要同時(shí)定義相應(yīng)的 actionType 然后再寫相關(guān)的 reducer。例如當(dāng)添加一個(gè)異步加載事件時(shí),需要同時(shí)定義加載中、加載失敗以及加載完成三個(gè) actionType,需要一個(gè)相對應(yīng)的 reducer 通過 switch 分支來處理對應(yīng)的 actionType,冗余代碼過多;
  • 目前已經(jīng)存在著非常多的解決方案,比如dva redux-tookit等。
  • 更新效率問題:由于使用不可變數(shù)據(jù)模式,每次更新 state 都需要拷貝一份完整的 state 造成了內(nèi)存的浪費(fèi)以及性能的損耗。
  • 其實(shí) redux 以及 react-redux 中內(nèi)部已做優(yōu)化,開發(fā)的時(shí)候使用 shouldComponentUpdate 等優(yōu)化方法也可以應(yīng)用,也可以用不可變數(shù)據(jù)結(jié)構(gòu)如 immutable、Immr 等來解決拷貝開銷問題。

以上就是React redux 原理及使用詳解的詳細(xì)內(nèi)容,更多關(guān)于React redux原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React?Native?中處理?Android?手機(jī)吞字的解決方案

    React?Native?中處理?Android?手機(jī)吞字的解決方案

    這篇文章主要介紹了React?Native?中處理?Android?手機(jī)吞字的解決方案,作者在 React Native 0.67.4 環(huán)境下,編寫了一個(gè)小 demo 來復(fù)現(xiàn)這個(gè)問題,需要的朋友可以參考下
    2022-08-08
  • React中的Component組件詳解

    React中的Component組件詳解

    本章節(jié),我們將一起探討 React 中類組件和函數(shù)組件的定義,不同組件的通信方式,以及常規(guī)組件的強(qiáng)化方式,幫助你全方位認(rèn)識 React 組件,從而對 React 的底層邏輯有進(jìn)一步的理解,感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • React腳手架搭建的學(xué)習(xí)

    React腳手架搭建的學(xué)習(xí)

    本文主要介紹了React腳手架搭建的學(xué)習(xí),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • React中setState使用原理解析

    React中setState使用原理解析

    這篇文章主要介紹了React中的setState使用細(xì)節(jié)和原理解析,主要包括使用setstate的原因及基本用法,本文通過實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下
    2022-10-10
  • react實(shí)現(xiàn)導(dǎo)航欄二級聯(lián)動

    react實(shí)現(xiàn)導(dǎo)航欄二級聯(lián)動

    這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)導(dǎo)航欄二級聯(lián)動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • react中的useContext具體實(shí)現(xiàn)

    react中的useContext具體實(shí)現(xiàn)

    useContext是React提供的一個(gè)鉤子函數(shù),用于在函數(shù)組件中訪問和使用Context,useContext的實(shí)現(xiàn)原理涉及React內(nèi)部的機(jī)制,本文給大家介紹react中的useContext具體實(shí)現(xiàn),感興趣的朋友一起看看吧
    2023-11-11
  • React實(shí)現(xiàn)組件全屏化的操作方法

    React實(shí)現(xiàn)組件全屏化的操作方法

    開發(fā)今天給我提了一個(gè)sql編輯器輸入框比較小,不支持放大,不太方便,下面看下我的處理方法,本文基于React+antd,給大家演示一個(gè)完整的全屏demo,感興趣的朋友一起看看吧
    2021-10-10
  • 深入了解React中的虛擬DOM

    深入了解React中的虛擬DOM

    歡迎來到今天的探險(xiǎn)之旅!在這篇博客中,我們將深入了解 React 中神奇的虛擬DOM,并通過一個(gè)簡單的例子來揭開其神秘面紗,文中通過代碼示例也講解非常詳細(xì),感興趣的朋友可以參考下
    2024-01-01
  • 一文掌握React?組件樹遍歷技巧

    一文掌握React?組件樹遍歷技巧

    這篇文章主要為大家介紹了React?組件樹遍歷技巧的掌握,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • React router cache route實(shí)現(xiàn)緩存頁面流程介紹

    React router cache route實(shí)現(xiàn)緩存頁面流程介紹

    react-router自身沒有路由緩存的特性,在5.x版本之前,我們可以基于react-router-cache-route來實(shí)現(xiàn)路由緩存功能。但是react-router 6.x在實(shí)現(xiàn)上做了比較大的變化,react-router-cache-route沒有提供相應(yīng)的支持
    2023-01-01

最新評論

双牌县| 余江县| 秦安县| 杨浦区| 竹北市| 喜德县| 军事| 项城市| 黄石市| 博乐市| 夏河县| 唐山市| 延吉市| 溆浦县| 商丘市| 金阳县| 启东市| 镇安县| 平陆县| 察雅县| 余干县| 玛沁县| 湖南省| 宜都市| 高台县| 武汉市| 洮南市| 巴楚县| 石屏县| 祁连县| 文山县| 临潭县| 济南市| 江阴市| 内乡县| 高雄市| 邮箱| 绵阳市| 尉氏县| 山东省| 宁夏|