Redux 中的异步操作:redux-saga vs redux-thunk
在前端开发中,异步操作是非常常见的一项任务,包括网络请求、数据获取和处理等等。为了更好的处理异步操作,Redux 也提供了多个工具来实现,其中最常用的两个是 redux-saga 和 redux-thunk。本文将会详细介绍这两个工具的使用和区别,并提供示例代码供读者参考。
1. Redux-thunk
Redux-thunk 是 Redux 官方推荐的中间件之一,它的作用是让 Redux 可以处理异步操作。在 Redux-thunk 中,我们可以将一个 action 变为一个函数,这个函数可以接受 dispatch 和 getState 两个参数,并且可以在其中进行异步操作。下面是一个使用 Redux-thunk 的示例代码:
// www.javascriptcn.com code example
// actions.js
const fetchUser = () => (dispatch, getState) => {
dispatch({ type: 'FETCH_REQUEST' });
fetch('/api/user')
.then(res => res.json())
.then(data => {
dispatch({ type: 'FETCH_SUCCESS', payload: data });
})
.catch(err => {
dispatch({ type: 'FETCH_FAILURE', payload: err });
});
};
// reducers.js
const userReducer = (state = { isLoading: false, data: null, error: null }, action) => {
switch (action.type) {
case 'FETCH_REQUEST':
return { isLoading: true, data: null, error: null };
case 'FETCH_SUCCESS':
return { isLoading: false, data: action.payload, error: null };
case 'FETCH_FAILURE':
return { isLoading: false, data: null, error: action.payload };
default:
return state;
}
};
export default userReducer;在上述代码中,我们定义了一个 fetchUser 函数,它接受 dispatch 和 getState 两个参数,在函数中发起了一个异步请求,并根据请求结果分发不同的 action。在 reducer 中,我们定义了一个 userReducer,它会根据不同的 action 来更新 state 中的数据。
总的来说,Redux-thunk 看起来比较简单、直接,适合处理一些简单的异步操作。但是,在复杂的场景下,Redux-thunk 的缺点也比较明显,比如:整个应用中只有一个全局的 thunk 中间件,如果我们需要处理多个异步操作,就需要编写大量的 thunk 函数,会导致代码冗长、难以维护。
2. Redux-saga
Redux-saga 是另一种处理异步操作的中间件。不过,和 Redux-thunk 不同的是,Redux-saga 使用了 ES6 的生成器函数(generator function)来实现异步操作的流程控制。因此,Redux-saga 不仅可以处理异步操作,还可以处理复杂的流程逻辑。下面是一个使用 Redux-saga 的示例代码:
// www.javascriptcn.com code example
// actions.js
const fetchUserRequest = () => ({ type: 'FETCH_USER_REQUEST' });
const fetchUserSuccess = (data) => ({ type: 'FETCH_USER_SUCCESS', payload: data });
const fetchUserFailure = (error) => ({ type: 'FETCH_USER_FAILURE', payload: error });
// sagas.js
import { call, put, takeLatest } from 'redux-saga/effects';
import { fetchUser } from './api';
function* fetchUserSaga(action) {
try {
yield put(fetchUserRequest());
const data = yield call(fetchUser, action.payload);
yield put(fetchUserSuccess(data));
} catch (e) {
yield put(fetchUserFailure(e));
}
}
function* userSaga() {
yield takeLatest('FETCH_USER', fetchUserSaga);
}
export default userSaga;
// reducers.js
const userReducer = (state = { isLoading: false, data: null, error: null }, action) => {
switch (action.type) {
case 'FETCH_USER_REQUEST':
return { isLoading: true, data: null, error: null };
case 'FETCH_USER_SUCCESS':
return { isLoading: false, data: action.payload, error: null };
case 'FETCH_USER_FAILURE':
return { isLoading: false, data: null, error: action.payload };
default:
return state;
}
};
export default userReducer;在上述代码中,我们定义了三个不同的 action,分别表示异步操作开始、成功和失败。在 sagas.js 中,我们定义了一个 fetchUserSaga,它接受一个 action,表示要进行异步操作,并使用 ES6 的 generator function 进行异步操作的流程控制。在 userSaga 函数中,我们使用 Redux-saga 提供的 takeLatest 方法,监听 FETCH_USER action,并在触发 action 后执行 fetchUserSaga 函数。在 reducer 中,我们根据不同的 action 更新 state 中的数据。
总的来说,Redux-saga 可以更好的处理异步操作,尤其是复杂的异步操作。使用 generator function 能够简化异步操作的流程控制,而 takeLatest 方法则能够减少重复的请求。不过,由于 Redux-saga 使用了 ES6 的 generator function 和 Redux-thunk 的普通函数不同,因此需要一些学习成本。
3. 总结
综上所述,Redux-thunk 和 Redux-saga 都是处理异步操作的中间件,具有各自的优缺点。使用 Redux-thunk 可以处理简单的异步操作,使用 Redux-saga 可以处理复杂的异步操作和流程控制。但是,Redux-thunk 在处理多个异步操作时代码比较冗长,而 Redux-saga 学习成本比较高。在实际开发中,应该根据具体情况选择合适的中间件。
注:完整代码可以在 GitHub 找到。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/65b358bfadd4f0e0ffc68812