亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

一篇文章介紹redux、react-redux、redux-saga總結

2024-05-06 16:51:19
字體:
來源:轉載
供稿:網友

本篇主要將react全家桶的產品非常精煉的提取了核心內容,精華程度堪比精油。各位大人,既然來了,客官您坐,來人,給客官看茶~~

redux

前言

首先,本篇文章要求您對js,react等知識有一定的了解,如果不曾了解,建議您先看一下:React精髓!一篇全概括(急速)

React有props和state:

  1. props意味著父級分發下來的屬性
  2. state意味著組件內部可以自行管理的狀態,并且整個React沒有數據向上回溯的能力,這就是react的單向數據流

這就意味著如果是一個數據狀態非常復雜的應用,更多的時候發現React根本無法讓兩個組件互相交流,使用對方的數據,react的通過層級傳遞數據的這種方法是非常難受的,這個時候,迫切需要一個機制,把所有的state集中到組件頂部,能夠靈活的將所有state各取所需的分發給所有的組件,是的,這就是redux

簡介

  1. redux是的誕生是為了給 React 應用提供「可預測化的狀態管理」機制。
  2. Redux會將整個應用狀態(其實也就是數據)存儲到到一個地方,稱為store
  3. 這個store里面保存一棵狀態樹(state tree)
  4. 組件改變state的唯一方法是通過調用store的dispatch方法,觸發一個action,這個action被對應的reducer處理,于是state完成更新
  5. 組件可以派發(dispatch)行為(action)給store,而不是直接通知其它組件
  6. 其它組件可以通過訂閱store中的狀態(state)來刷新自己的視圖

使用步驟

創建reducer

  • 可以使用單獨的一個reducer,也可以將多個reducer合并為一個reducer,即:combineReducers()
  • action發出命令后將state放入reucer加工函數中,返回新的state,對state進行加工處理

創建action

  • 用戶是接觸不到state的,只能有view觸發,所以,這個action可以理解為指令,需要發出多少動作就有多少指令
  • action是一個對象,必須有一個叫type的參數,定義action類型

創建的store,使用createStore方法

  • store 可以理解為有多個加工機器的總工廠
  • 提供subscribe,dispatch,getState這些方法。

按步驟手把手實戰。

上述步驟,對應的序號,我會在相關代碼標出

npm install redux -S // 安裝import { createStore } from 'redux' // 引入const reducer = (state = {count: 0}, action) => {----------> ⑴ switch (action.type){ case 'INCREASE': return {count: state.count + 1}; case 'DECREASE': return {count: state.count - 1}; default: return state; }}const actions = {---------->⑵ increase: () => ({type: 'INCREASE'}), decrease: () => ({type: 'DECREASE'})}const store = createStore(reducer);---------->⑶store.subscribe(() => console.log(store.getState()));store.dispatch(actions.increase()) // {count: 1}store.dispatch(actions.increase()) // {count: 2}store.dispatch(actions.increase()) // {count: 3}

自己畫了一張非常簡陋的流程圖,方便理解redux的工作流程

redux,react-redux,redux-saga

react-redux

剛開始就說了,如果把store直接集成到React應用的頂層props里面,只要各個子組件能訪問到頂層props就行了,比如這樣:

<頂層組件 store={store}> <App /></頂層組件>

不就ok了嗎?這就是 react-redux。Redux 官方提供的 React 綁定庫。 具有高效且靈活的特性。

React Redux 將組件區分為 容器組件 和 UI 組件

  1. 前者會處理邏輯
  2. 后者只負責顯示和交互,內部不處理邏輯,狀態完全由外部掌控

兩個核心

Provider

看我上邊那個代碼的頂層組件4個字。對,你沒有猜錯。這個頂級組件就是Provider,一般我們都將頂層組件包裹在Provider組件之中,這樣的話,所有組件就都可以在react-redux的控制之下了,但是store必須作為參數放到Provider組件中去

<Provider store = {store}> <App /><Provider>

這個組件的目的是讓所有組件都能夠訪問到Redux中的數據。

connect

這個才是react-redux中比較難的部分,我們詳細解釋一下

首先,先記住下邊的這行代碼:

connect(mapStateToProps, mapDispatchToProps)(MyComponent)

mapStateToProps

這個單詞翻譯過來就是把state映射到props中去 ,其實也就是把Redux中的數據映射到React中的props中去。
舉個栗子:

 const mapStateToProps = (state) => {  return {  // prop : state.xxx | 意思是將state中的某個數據映射到props中  foo: state.bar  } }

然后渲染的時候就可以使用this.props.foo

class Foo extends Component { constructor(props){  super(props); } render(){  return(   // 這樣子渲染的其實就是state.bar的數據了   <div>this.props.foo</div>  ) }}Foo = connect()(Foo);export default Foo;

然后這樣就可以完成渲染了

mapDispatchToProps

這個單詞翻譯過來就是就是把各種dispatch也變成了props讓你可以直接使用

const mapDispatchToProps = (dispatch) => { // 默認傳遞參數就是dispatch return { onClick: () => {  dispatch({  type: 'increatment'  }); } };}
class Foo extends Component { constructor(props){  super(props); } render(){  return(       <button onClick = {this.props.onClick}>點擊increase</button>  ) }}Foo = connect()(Foo);export default Foo;

組件也就改成了上邊這樣,可以直接通過this.props.onClick,來調用dispatch,這樣子就不需要在代碼中來進行store.dispatch了

react-redux的基本介紹就到這里了

redux-saga

如果按照原始的redux工作流程,當組件中產生一個action后會直接觸發reducer修改state,reducer又是一個純函數,也就是不能再reducer中進行異步操作;

而往往實際中,組件中發生的action后,在進入reducer之前需要完成一個異步任務,比如發送ajax請求后拿到數據后,再進入reducer,顯然原生的redux是不支持這種操作的

這個時候急需一個中間件來處理這種業務場景,目前最優雅的處理方式自然就是redux-saga

核心講解

1、Saga 輔助函數

redux-saga提供了一些輔助函數,用來在一些特定的action 被發起到Store時派生任務,下面我先來講解兩個輔助函數:takeEvery 和 takeLatest

takeEvery

takeEvery就像一個流水線的洗碗工,過來一個臟盤子就直接執行后面的洗碗函數,一旦你請了這個洗碗工他會一直執行這個工作,絕對不會停止接盤子的監聽過程和觸發洗盤子函數

例如:每次點擊  按鈕去Fetch獲取數據時時,我們發起一個 FETCH_REQUESTED 的 action。 我們想通過啟動一個任務從服務器獲取一些數據,來處理這個action,類似于

window.addEventLister('xxx',fn)

當dispatch xxx的時候,就會執行fn方法,

首先我們創建一個將執行異步 action 的任務(也就是上邊的fn):

// put:你就認為put就等于 dispatch就可以了;// call:可以理解為實行一個異步函數,是阻塞型的,只有運行完后面的函數,才會繼續往下;// 在這里可以片面的理解為async中的await!但寫法直觀多了!import { call, put } from 'redux-saga/effects'export function* fetchData(action) { try {  const apiAjax = (params) => fetch(url, params);  const data = yield call(apiAjax);  yield put({type: "FETCH_SUCCEEDED", data}); } catch (error) {  yield put({type: "FETCH_FAILED", error}); }}

然后在每次 FETCH_REQUESTED action 被發起時啟動上面的任務,也就相當于每次觸發一個名字為 FETCH_REQUESTED 的action就會執行上邊的任務,代碼如下

import { takeEvery } from 'redux-saga'function* watchFetchData() { yield* takeEvery("FETCH_REQUESTED", fetchData)}

注意:上面的 takeEvery 函數可以使用下面的寫法替換

function* watchFetchData() {  while(true){  yield take('FETCH_REQUESTED');  yield fork(fetchData); }}

takeLatest

在上面的例子中,takeEvery 允許多個 fetchData 實例同時啟動,在某個特定時刻,我們可以啟動一個新的 fetchData 任務, 盡管之前還有一個或多個 fetchData 尚未結束

如果我們只想得到最新那個請求的響應(例如,始終顯示最新版本的數據),我們可以使用 takeLatest 輔助函數

import { takeLatest } from 'redux-saga'function* watchFetchData() { yield* takeLatest('FETCH_REQUESTED', fetchData)}

和takeEvery不同,在任何時刻 takeLatest 只允許執行一個 fetchData 任務,并且這個任務是最后被啟動的那個,如果之前已經有一個任務在執行,那之前的這個任務會自動被取消

2、Effect Creators

redux-saga框架提供了很多創建effect的函數,下面我們就來簡單的介紹下開發中最常用的幾種

  • take(pattern)
  • put(action)
  • call(fn, ...args)
  • fork(fn, ...args)
  • select(selector, ...args)

take(pattern)

take函數可以理解為監聽未來的action,它創建了一個命令對象,告訴middleware等待一個特定的action, Generator會暫停,直到一個與pattern匹配的action被發起,才會繼續執行下面的語句,也就是說,take是一個阻塞的 effect

用法:

function* watchFetchData() { while(true) { // 監聽一個type為 'FETCH_REQUESTED' 的action的執行,直到等到這個Action被觸發,才會接著執行下面的 yield fork(fetchData) 語句  yield take('FETCH_REQUESTED');  yield fork(fetchData); }}

put(action)

put函數是用來發送action的 effect,你可以簡單的把它理解成為redux框架中的dispatch函數,當put一個action后,reducer中就會計算新的state并返回,注意: put 也是阻塞 effect

用法:

export function* toggleItemFlow() { let list = [] // 發送一個type為 'UPDATE_DATA' 的Action,用來更新數據,參數為 `data:list` yield put({  type: actionTypes.UPDATE_DATA,  data: list })}

call(fn, ...args)

call函數你可以把它簡單的理解為就是可以調用其他函數的函數,它命令 middleware 來調用fn 函數, args為函數的參數,注意:  fn 函數可以是一個 Generator 函數,也可以是一個返回 Promise 的普通函數,call 函數也是阻塞 effect

用法:

export const delay = ms => new Promise(resolve => setTimeout(resolve, ms))export function* removeItem() { try { // 這里call 函數就調用了 delay 函數,delay 函數為一個返回promise 的函數 return yield call(delay, 500) } catch (err) { yield put({type: actionTypes.ERROR}) }}

fork(fn, ...args)

fork 函數和 call 函數很像,都是用來調用其他函數的,但是fork函數是非阻塞函數,也就是說,程序執行完 yield fork(fn, args) 這一行代碼后,會立即接著執行下一行代碼語句,而不會等待fn函數返回結果后,在執行下面的語句

用法:

import { fork } from 'redux-saga/effects'export default function* rootSaga() { // 下面的四個 Generator 函數會一次執行,不會阻塞執行 yield fork(addItemFlow) yield fork(removeItemFlow) yield fork(toggleItemFlow) yield fork(modifyItem)}

select(selector, ...args)

select 函數是用來指示 middleware調用提供的選擇器獲取Store上的state數據,你也可以簡單的把它理解為redux框架中獲取store上的 state數據一樣的功能 :store.getState()

用法:

export function* toggleItemFlow() {  // 通過 select effect 來獲取 全局 state上的 `getTodoList` 中的 list  let tempList = yield select(state => state.getTodoList.list)}

一個具體的實例

**index.js **

import React from 'react';import ReactDOM from 'react-dom';import {createStore, applyMiddleware} from 'redux'import createSagaMiddleware from 'redux-saga'import rootSaga from './sagas'import Counter from './Counter'import rootReducer from './reducers'const sagaMiddleware = createSagaMiddleware() // 創建了一個saga中間件實例// 下邊這句話和下邊的兩行代碼創建store的方式是一樣的// const store = createStore(reducers,applyMiddlecare(middlewares))const createStoreWithMiddleware = applyMiddleware(middlewares)(createStore)const store = createStoreWithMiddleware(rootReducer)sagaMiddleware.run(rootSaga)const action = type => store.dispatch({ type })function render() { ReactDOM.render( <Counter  value={store.getState()}  onIncrement={() => action('INCREMENT')}  onDecrement={() => action('DECREMENT')}  onIncrementAsync={() => action('INCREMENT_ASYNC')} />, document.getElementById('root') )}render()store.subscribe(render)

sagas.js

import { put, call, take,fork } from 'redux-saga/effects';import { takeEvery, takeLatest } from 'redux-saga'export const delay = ms => new Promise(resolve => setTimeout(resolve, ms));function* incrementAsync() { // 延遲 1s 在執行 + 1操作 yield call(delay, 1000); yield put({ type: 'INCREMENT' });}export default function* rootSaga() { // while(true){ // yield take('INCREMENT_ASYNC'); // yield fork(incrementAsync); // } // 下面的寫法與上面的寫法上等效 yield* takeEvery("INCREMENT_ASYNC", incrementAsync)}

reducer.js

export default function counter(state = 0, action) { switch (action.type) { case 'INCREMENT':  return state + 1 case 'DECREMENT':  return state - 1 case 'INCREMENT_ASYNC':  return state default:  return state }}

從上面的代碼結構可以看出,redux-saga的使用方式還是比較簡單的,相比較之前的redux框架的CounterApp,多了一個sagas的文件,reducers文件還是之前的使用方式

redux-saga基本用法總結:

  • 使用 createSagaMiddleware 方法創建 saga 的 Middleware ,然后在創建的 redux 的 store 時,使用 applyMiddleware 函數將創建的 saga Middleware 實例綁定到 store 上,最后可以調用 saga Middleware 的 run 函數來執行某個或者某些 Middleware 。
  • 在 saga 的 Middleware 中,可以使用 takeEvery 或者 takeLatest 等 API 來監聽某個 action ,當某個 action 觸發后, saga 可以使用 call 發起異步操作,操作完成后使用 put 函數觸發 action ,同步更新 state ,從而完成整個 State 的更新。

ok,故事到這里就接近尾聲了,以上主要介紹了redux,react-redux和redux-saga目前redux全家桶主流的一些產品,接下來,主要會產出一下根據源碼,手寫一下redux和react-redux的輪子

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美高清电影在线看| 色综合天天狠天天透天天伊人| 国产成人精品电影| 亚洲经典中文字幕| 欧美高跟鞋交xxxxxhd| 亚洲社区在线观看| 久久影院模特热| 一区二区av在线| 亚洲欧美在线一区二区| 久久久久久久久久久av| 久久久国产成人精品| 91亚洲精品一区二区| 亚洲人成免费电影| 精品二区三区线观看| 中文字幕在线观看亚洲| 色综合久久悠悠| 国产精品久久久一区| 国产成人一区二区三区电影| 亚洲mm色国产网站| 韩国三级电影久久久久久| 国产精品热视频| 欧美精品在线极品| 久久国产加勒比精品无码| 久久99国产综合精品女同| 亚洲成人黄色在线| 精品色蜜蜜精品视频在线观看| 国产视频精品一区二区三区| 8050国产精品久久久久久| 国产精品高清在线观看| 欧美激情精品久久久久久黑人| 国产视频久久久久久久| 亚洲精品国产精品久久清纯直播| 少妇高潮久久77777| 伊人男人综合视频网| 亚洲网站在线播放| 在线一区二区日韩| 国产精品福利无圣光在线一区| 欧美刺激性大交免费视频| 成人免费福利视频| 91国产精品视频在线| 精品久久久一区二区| 亚洲免费视频观看| 亚洲欧美一区二区三区久久| 尤物tv国产一区| 理论片在线不卡免费观看| 国产999视频| 欧美在线国产精品| 欧美视频在线免费| 亚洲国产精品va在线看黑人| 国产精品爽爽爽爽爽爽在线观看| 国产午夜精品全部视频在线播放| 精品国产美女在线| 精品国产拍在线观看| 久久久久久久久久久人体| 91精品久久久久久| 久久久精品亚洲| 日韩欧美精品中文字幕| 亚洲激情视频网站| 97欧美精品一区二区三区| 国产z一区二区三区| 日韩精品视频在线播放| 欧美日韩一区二区在线播放| 色综合久综合久久综合久鬼88| 日本欧美中文字幕| 亚洲精品91美女久久久久久久| 亚洲成成品网站| 久久免费视频这里只有精品| 亚洲91av视频| 国产精品ⅴa在线观看h| 美女视频久久黄| 久久天堂av综合合色| 亚洲精品v欧美精品v日韩精品| 精品欧美国产一区二区三区| 在线播放日韩精品| 97av在线视频免费播放| 国产一区二区三区三区在线观看| 久久成人国产精品| 97免费视频在线播放| 亚洲美女免费精品视频在线观看| 福利二区91精品bt7086| 91视频国产一区| 日韩大片在线观看视频| 人妖精品videosex性欧美| 久久久噜噜噜久久中文字免| 亚洲成色www8888| 欧美国产精品日韩| 久久久久999| 日本欧美精品在线| 国产成人精品在线观看| 日韩免费在线电影| 亚洲激情第一页| 国产日韩综合一区二区性色av| 日韩精品欧美激情| 精品久久久国产| 2020久久国产精品| 久久成人av网站| 日韩免费观看在线观看| 日韩欧美亚洲成人| 91久久精品日日躁夜夜躁国产| 欧美日韩免费一区| 亚洲自拍高清视频网站| 亚洲免费一级电影| 日韩一区二区三区在线播放| 91av在线不卡| 亚洲精品国精品久久99热| 久久久亚洲国产| 亚洲精品日韩激情在线电影| 在线亚洲国产精品网| 国产精品福利小视频| 亚洲韩国日本中文字幕| 国产亚洲精品激情久久| 91在线色戒在线| 国语自产精品视频在免费| 国产精品美女久久久久av超清| 亚洲最新视频在线| 中文字幕成人精品久久不卡| 久久精品最新地址| 久久福利视频网| 欧美精品手机在线| 奇米4444一区二区三区| 精品久久久久久中文字幕| 日韩成人久久久| 国产精品自产拍在线观看| 九九九久久久久久| 国产亚洲精品久久久久久| 2018日韩中文字幕| 亚洲人av在线影院| 在线视频亚洲欧美| 懂色aⅴ精品一区二区三区蜜月| www.亚洲天堂| 亚洲欧洲日韩国产| 青青久久av北条麻妃黑人| 日韩理论片久久| 国产免费一区二区三区香蕉精| 欧美理论片在线观看| 国产亚洲美女久久| 91视频国产精品| 色综合色综合久久综合频道88| 久久精品国产亚洲一区二区| 欧美中文在线字幕| 久久久国产精品亚洲一区| 久久久久日韩精品久久久男男| 亚洲丁香婷深爱综合| 成人免费福利在线| 91精品91久久久久久| 国产精品丝袜高跟| 亚洲国产古装精品网站| 91免费版网站入口| 欧美老少做受xxxx高潮| 亚洲女同精品视频| 亚洲国产精品系列| 国产一区二区成人| 亚洲第一av在线| 国产精品羞羞答答| 一区二区三区 在线观看视| 欧美区在线播放| 久久久久这里只有精品| 97在线免费视频| 欧美床上激情在线观看| 精品露脸国产偷人在视频| 国产精品免费小视频| 久久久中精品2020中文| 精品国偷自产在线| 777午夜精品福利在线观看|