이 글은 redux-saga의 첫 소개와 사용법을 주로 소개하고 참고자료를 제공합니다.
redux-saga는 Redux 애플리케이션의 비동기 작업을 관리하는 미들웨어입니다. 해당 기능은 redux-thunk + async/await와 유사하며 Sagas를 생성하여 중앙 집중식 처리를 위해 모든 비동기 작업 논리를 한 곳에 저장합니다.
redux-saga 효과
redux-saga 효과는 saga 미들웨어에 의해 실행될 몇 가지 지침이 포함된 일반 텍스트 JavaScript 개체입니다. 이러한 지침에 의해 수행되는 작업에는 다음 세 가지 유형이 포함됩니다.
비동기 호출 시작(예: Ajax 요청 전송)
스토어 업데이트를 위한 다른 작업 시작
다른 Sagas 호출
Effects에는 비동기 API 참조에서 찾을 수 있는 많은 지침이 포함되어 있습니다. redux-saga의 기능은 테스트에 편리합니다. 처리를 위해 saga에 집중되어 있습니다
watch/worker(듣기->실행) 작업 형식
은 생성기로 구현됩니다
assert.deepEqual(iterator.next().value, call(Api.fetch, '/products'))
// 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 并行 }) }
동시에 여러 작업을 수행하세요
동시에 여러 작업을 수행해야 하는 시나리오가 발생하는 경우, 다음과 같습니다. 사용자 데이터 및 상품 데이터를 요청할 때 다음 방법을 사용해야 합니다.
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')) } } }
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')
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 的对象,便于后续的遍历和执行, 在此不具体分析。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
위 내용은 redux-saga를 사용하는 방법과 redux-saga를 사용하는 방법과 기술은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!