>웹 프론트엔드 >JS 튜토리얼 >redux-saga를 사용하는 방법과 redux-saga를 사용하는 방법과 기술은 무엇입니까?

redux-saga를 사용하는 방법과 redux-saga를 사용하는 방법과 기술은 무엇입니까?

亚连
亚连원래의
2018-05-31 14:13:393868검색

이 글은 redux-saga의 첫 소개와 사용법을 주로 소개하고 참고자료를 제공합니다.

redux-saga는 Redux 애플리케이션의 비동기 작업을 관리하는 미들웨어입니다. 해당 기능은 redux-thunk + async/await와 유사하며 Sagas를 생성하여 중앙 집중식 처리를 위해 모든 비동기 작업 논리를 한 곳에 저장합니다.

redux-saga 효과

redux-saga 효과는 saga 미들웨어에 의해 실행될 몇 가지 지침이 포함된 일반 텍스트 JavaScript 개체입니다. 이러한 지침에 의해 수행되는 작업에는 다음 세 가지 유형이 포함됩니다.

  1. 비동기 호출 시작(예: Ajax 요청 전송)

  2. 스토어 업데이트를 위한 다른 작업 시작

  3. 다른 Sagas 호출

Effects에는 비동기 API 참조에서 찾을 수 있는 많은 지침이 포함되어 있습니다. redux-saga의 기능은 테스트에 편리합니다. 처리를 위해 saga에 집중되어 있습니다

watch/worker(듣기->실행) 작업 형식

은 생성기로 구현됩니다

복잡한 비동기 논리가 포함된 애플리케이션 시나리오를 잘 지원합니다

  1. 비동기 논리 구현 보다 세분화된 방식으로 프로세스를 더욱 명확하고 쉽게 버그를 추적하고 해결할 수 있습니다.

  2. 인간의 사고 논리에 더 가까운 동기 방식으로 비동기 논리를 작성하세요

  3. redux-thunk에서 redux-saga로

  4. 이제 시나리오가 있다고 가정해 보겠습니다. 사용자는 로그인 시 사용자 이름과 비밀번호가 요구 사항을 충족합니다.

  5. redux-thunk를 사용하여 구현

  6. 사용자 데이터 획득 논리(user.js):

  7. assert.deepEqual(iterator.next().value, call(Api.fetch, '/products'))
  8. 로그인 확인 논리(login.js):

// 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 });
  }
}

redux-saga

모든 비동기 로직은 saga.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 });
  }
}

해석하기 어려움

redux-saga의 경우 여전히 어렵고 모호한 부분이 많습니다. 장소 이해하기 위해 저자는 혼동하기 쉬운 개념을 다음과 같이 정리했습니다. take

take 및 takeEvery의 사용은 둘 다 특정 작업을 모니터링하지만 해당 기능은 일관성이 없습니다. takeEvery는 작업이 수행될 때마다 응답합니다. 그리고 take는 실행 흐름이 take 문에 도달할 때만 응답합니다. takeEvery는 액션을 듣고 해당 처리 기능을 실행하기만 하며 액션이 실행되는 시점과 액션에 응답하는 방법을 제어할 수 없습니다. 청취는 작업이 일치할 때마다 계속해서 호출될 수 있습니다. 그러나 Take는 생성기 함수에서 응답 후 작업과 후속 작업에 응답할 시기를 결정할 수 있습니다.

예를 들어 모든 유형의 작업 트리거를 모니터링할 때 로거 작업을 수행하려면 takeEvery를 사용하여 다음을 구현합니다.

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 });
 }
}

take를 사용하여 다음을 구현합니다.

import { takeEvery } from 'redux-saga'

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

여기서 while(true)는 의미합니다. 프로세스의 끝에 도달하면 한 단계(로거)는 새로운 임의 작업을 기다리면서 새로운 반복(로거 프로세스)을 시작합니다.

차단 및 비차단


호출 작업은 비동기 작업을 시작하는 데 사용됩니다. 생성기의 경우 호출은 생성기 호출이 끝나기 전에는 다른 작업을 실행하거나 처리할 수 없습니다. 그러나 포크는 비차단 작업입니다. 포크가 작업을 동원할 때 작업은 백그라운드에서 실행되며 결과가 반환될 때까지 기다리지 않고 실행 흐름을 계속 실행할 수 있습니다.

예를 들어 다음 로그인 시나리오는 다음과 같습니다.

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

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

인증 요청 호출 시 결과가 반환되지 않지만 사용자가 이때 LOGOUT 작업을 트리거하면 이때의 LOGOUT은 무시되고 인증되지 않습니다. loginFlow가 Authorize에서 차단되고 take('LOGOUT')에 실행되지 않기 때문에 처리 중입니다.

동시에 여러 작업을 수행하세요

동시에 여러 작업을 수행해야 하는 시나리오가 발생하는 경우, 다음과 같습니다. 사용자 데이터 및 상품 데이터를 요청할 때 다음 방법을 사용해야 합니다.

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'))
  }
 }
}

yield 뒤에 배열이 오면 해당 배열의 작업은 Promise.all의 실행 규칙에 따라 실행되며, 생성기는 모든 효과가 실행될 때까지 차단됩니다.

소스 코드 해석

redux-saga를 사용하는 모든 프로젝트에서 기본 파일에는 sagas 미들웨어를 Store에 추가하는 다음 논리가 있습니다.

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')

createSagaMiddleware가 redux인 경우 - Saga 핵심 소스 코드 파일 src/middleware.js에서 내보낸 메서드:

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

这段逻辑主要是执行了 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
}

这个函数里定义了返回了一个 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)
   } 
 ...
 }
}

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

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

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

相关文章:

JavaScript 隐性类型转换步骤浅析

JavaScript的数据类型转换原则

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

위 내용은 redux-saga를 사용하는 방법과 redux-saga를 사용하는 방법과 기술은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.