Heim > Web-Frontend > js-Tutorial > Hauptteil

Wie verwende ich Redux-Saga und welche Methoden und Techniken gibt es für die Verwendung von Redux-Saga?

亚连
Freigeben: 2018-05-31 14:13:39
Original
3768 Leute haben es durchsucht

Dieser Artikel stellt hauptsächlich die erste Einführung und Verwendung von Redux-Saga vor. Jetzt teile ich ihn mit Ihnen und gebe Ihnen eine Referenz.

redux-saga ist eine Middleware, die asynchrone Vorgänge von Redux-Anwendungen verwaltet. Ihre Funktion ähnelt redux-thunk + async/await. Sie speichert die gesamte asynchrone Betriebslogik an einem Ort für die zentrale Verarbeitung durch die Erstellung von Sagas.

Die Effekte von redux-saga

Die Effekte in redux-saga sind ein Nur-Text-JavaScript-Objekt, das einige Funktionen enthält, die ausgeführt werden durch die Saga-Middleware-Anweisung. Die von diesen Anweisungen ausgeführten Vorgänge umfassen die folgenden drei Typen:

  1. Initiieren eines asynchronen Aufrufs (z. B. Senden einer Ajax-Anfrage)

  2. Initiieren anderer Aktion zum Aktualisieren des Stores

  3. Andere Sagas aufrufen

Effects enthält viele Anweisungen, die in der asynchronen API-Referenz zu finden sind

Features von redux-saga

Komfort zum Testen, zum Beispiel:

assert.deepEqual(iterator.next().value, call(Api.fetch, '/products'))
Nach dem Login kopieren

  1. Aktion kann ihre Reinheit bewahren, und asynchrone Vorgänge werden in Saga zur Verarbeitung konzentriert

  2. Beobachtung/Arbeiter (Überwachung->Ausführung) Arbeitsform

  3. ist als Generator implementiert

  4. hat gute Unterstützung für Anwendungsszenarien mit komplexer asynchroner Logik

  5. Mehr Implementieren Sie asynchrone Logik auf feinkörnige Weise, um den Prozess klarer zu gestalten und die Verfolgung und Behebung von Fehlern zu erleichtern.

  6. Schreiben Sie asynchrone Logik auf synchrone Weise, die eher der menschlichen Denklogik entspricht

  7. Von Redux-Thunk zu Redux-Saga

Angenommen, es gibt jetzt ein Szenario: Wenn sich der Benutzer anmeldet, muss er überprüfen, ob der Benutzername und das Passwort des Benutzers den Anforderungen entsprechen.

Verwenden Sie Redux-Thunk, um

Die Logik zum Abrufen von Benutzerdaten (user.js) zu implementieren:

// user.js

import request from 'axios';

// define constants
// define initial state
// export default reducer

export const loadUserData = (uid) => async (dispatch) => {
  try {
    dispatch({ type: USERDATA_REQUEST });
    let { data } = await request.get(`/users/${uid}`);
    dispatch({ type: USERDATA_SUCCESS, data });
  } catch(error) {
    dispatch({ type: USERDATA_ERROR, error });
  }
}
Nach dem Login kopieren

Login-Verifizierungslogik (login.js):

import request from 'axios';
import { loadUserData } from './user';

export const login = (user, pass) => async (dispatch) => {
  try {
    dispatch({ type: LOGIN_REQUEST });
    let { data } = await request.post('/login', { user, pass });
    await dispatch(loadUserData(data.uid));
    dispatch({ type: LOGIN_SUCCESS, data });
  } catch(error) {
    dispatch({ type: LOGIN_ERROR, error });
  }
}
Nach dem Login kopieren

redux-saga

Alle asynchrone Logik kann in saga.js geschrieben werden:

export function* loginSaga() {
 while(true) {
  const { user, pass } = yield take(LOGIN_REQUEST) //等待 Store 上指定的 action LOGIN_REQUEST
  try {
   let { data } = yield call(loginRequest, { user, pass }); //阻塞,请求后台数据
   yield fork(loadUserData, data.uid); //非阻塞执行loadUserData
   yield put({ type: LOGIN_SUCCESS, data }); //发起一个action,类似于dispatch
  } catch(error) {
   yield put({ type: LOGIN_ERROR, error });
  } 
 }
}

export function* loadUserData(uid) {
 try {
  yield put({ type: USERDATA_REQUEST });
  let { data } = yield call(userRequest, `/users/${uid}`);
  yield put({ type: USERDATA_SUCCESS, data });
 } catch(error) {
  yield put({ type: USERDATA_ERROR, error });
 }
}
Nach dem Login kopieren

Schwierige Interpretation

Für die Redux-Saga gibt es immer noch viele Dinge, die schwer zu verstehen und unklar sind. Der Autor organisiert unten die Konzepte, die ich verwirrender finde:

Verwendung von take

Sowohl take als auch takeEvery überwachen eine Aktion, aber ihre Funktionen sind inkonsistent, takeEvery reagiert jedes Mal, wenn die Aktion ausgelöst wird, während take nur reagiert, wenn der Ausführungsfluss die take-Antwort erreicht. takeEvery hört nur auf die Aktion und führt die entsprechende Verarbeitungsfunktion aus. Es hat nicht viel Kontrolle darüber, wann die Aktion ausgeführt wird und wie auf die Aktion reagiert wird. Sie können nicht steuern, wann sie aufgerufen werden Zuhören. Es kann nur immer wieder aufgerufen werden, wenn eine Aktion abgeglichen wird. Take kann jedoch entscheiden, wann auf eine Aktion und die nachfolgenden Vorgänge nach der Antwort in der Generatorfunktion reagiert werden soll.
Um beispielsweise den Logger-Vorgang bei der Überwachung aller Arten von Aktionsauslösern durchzuführen, verwenden Sie takeEvery, um Folgendes zu implementieren:

import { takeEvery } from 'redux-saga'

function* watchAndLog(getState) {
 yield* takeEvery('*', function* logger(action) {
   //do some logger operation //在回调函数体内
 })
}
Nach dem Login kopieren

Verwenden Sie take, um Folgendes zu implementieren :

import { take } from 'redux-saga/effects'

function* watchAndLog(getState) {
 while(true) {
  const action = yield take('*')
  //do some logger operation //与 take 并行 
 })
}
Nach dem Login kopieren

Wobei (true) bedeutet, dass, sobald der letzte Schritt des Prozesses (Logger) erreicht ist, eine neue Iteration (Logger-Prozess) durch Warten gestartet wird für eine neue willkürliche Aktion.

Blockierend und nicht blockierend

Der Aufrufvorgang wird zum Initiieren asynchroner Vorgänge verwendet. Bei Generatoren ist der Aufruf ein blockierender Vorgang und kann erst ausgeführt werden, wenn der Generatoraufruf ausgeführt wird abgeschlossen. Führen oder bearbeiten Sie eine andere Angelegenheit. , aber Fork ist eine nicht blockierende Operation. Wenn Fork eine Aufgabe mobilisiert, wird die Aufgabe im Hintergrund ausgeführt. Zu diesem Zeitpunkt kann der Ausführungsfluss weiter ausgeführt werden, ohne auf die Rückgabe des Ergebnisses zu warten.

Zum Beispiel das folgende Anmeldeszenario:

function* loginFlow() {
 while(true) {
  const {user, password} = yield take('LOGIN_REQUEST')
  const token = yield call(authorize, user, password)
  if(token) {
   yield call(Api.storeItem({token}))
   yield take('LOGOUT')
   yield call(Api.clearItem('token'))
  }
 }
}
Nach dem Login kopieren

Wenn das Ergebnis beim Aufruf zur Autorisierungsanforderung nicht zurückgegeben wird, der Benutzer es jedoch auslöst Zu diesem Zeitpunkt wird erneut die Aktion „LOGOUT“ ausgeführt. Das Abmelden zu diesem Zeitpunkt wird ignoriert und nicht verarbeitet, da loginFlow in der Autorisierung blockiert ist und nicht ausgeführt wird. take('LOGOUT')

Führen Sie mehrere gleichzeitig aus Zeitaufgabe

Wenn Sie auf ein Szenario stoßen, in dem Sie mehrere Aufgaben gleichzeitig ausführen müssen, z. B. das Anfordern von Benutzerdaten und Produktdaten, sollten Sie die folgende Methode verwenden:

import { call } from 'redux-saga/effects'
//同步执行
const [users, products] = yield [
 call(fetch, '/users'),
 call(fetch, '/products')
]

//而不是
//顺序执行
const users = yield call(fetch, '/users'),
   products = yield call(fetch, '/products')
Nach dem Login kopieren

Wenn auf yield ein Array folgt, werden die Operationen im Array gemäß den Ausführungsregeln von Promise.all ausgeführt und der Generator blockiert, bis alle Effekte ausgeführt sind

Interpretation des Quellcodes

In jedem Projekt, das Redux-Saga verwendet, verfügt die Hauptdatei über die folgende Logik zum Hinzufügen von Sagas-Middleware zum Store:

const sagaMiddleware = createSagaMiddleware({sagaMonitor})
const store = createStore(
 reducer,
 applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(rootSaga)
Nach dem Login kopieren

Wobei createSagaMiddleware die in der Redux-Saga-Core-Quellcodedatei src/middleware.js exportierte Methode ist:

export default function sagaMiddlewareFactory({ context = {}, ...options } = {}) {
 ...
 
 function sagaMiddleware({ getState, dispatch }) {
  const channel = stdChannel()
  channel.put = (options.emitter || identity)(channel.put)

  sagaMiddleware.run = runSaga.bind(null, {
   context,
   channel,
   dispatch,
   getState,
   sagaMonitor,
   logger,
   onError,
   effectMiddlewares,
  })

  return next => action => {
   if (sagaMonitor && sagaMonitor.actionDispatched) {
    sagaMonitor.actionDispatched(action)
   }
   const result = next(action) // hit reducers
   channel.put(action)
   return result
  }
 }
 ...
 
 }
Nach dem Login kopieren

这段逻辑主要是执行了 sagaMiddleware(),该函数里面将 runSaga 赋值给 sagaMiddleware.run 并执行,最后返回 middleware。 接着看 runSaga() 的逻辑:

export function runSaga(options, saga, ...args) {
...
 const task = proc(
  iterator,
  channel,
  wrapSagaDispatch(dispatch),
  getState,
  context,
  { sagaMonitor, logger, onError, middleware },
  effectId,
  saga.name,
 )

 if (sagaMonitor) {
  sagaMonitor.effectResolved(effectId, task)
 }

 return task
}
Nach dem Login kopieren

这个函数里定义了返回了一个 task 对象,该 task 是由 proc 产生的,移步 proc.js:

export default function proc(
 iterator,
 stdChannel,
 dispatch = noop,
 getState = noop,
 parentContext = {},
 options = {},
 parentEffectId = 0,
 name = 'anonymous',
 cont,
) {
 ...
 const task = newTask(parentEffectId, name, iterator, cont)
 const mainTask = { name, cancel: cancelMain, isRunning: true }
 const taskQueue = forkQueue(name, mainTask, end)
 
 ...
 
 next()
 
 return task

 function next(arg, isErr){
 ...
   if (!result.done) {
    digestEffect(result.value, parentEffectId, '', next)
   } 
 ...
 }
}
Nach dem Login kopieren

其中 digestEffect 就执行了 effectTriggerd() 和 runEffect(),也就是执行 effect,其中 runEffect() 中定义了不同 effect 执行相对应的函数,每一个 effect 函数都在 proc.js 实现了。

除了一些核心方法之外,redux-saga 还提供了一系列的 helper 文件,这些文件的作用是返回一个类 iterator 的对象,便于后续的遍历和执行, 在此不具体分析。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JavaScript 隐性类型转换步骤浅析

JavaScript的数据类型转换原则

p5.js入门教程之小球动画示例代码

Das obige ist der detaillierte Inhalt vonWie verwende ich Redux-Saga und welche Methoden und Techniken gibt es für die Verwendung von Redux-Saga?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!