在前端开发中,一个应用的状态管理是非常重要的。而 Redux-Saga 框架就是为这个问题而生的解决方案之一。本篇文章将带你深入了解 Redux-Saga 框架,包括其基本概念、使用方法以及示例代码。
Redux-Saga 的基本概念
Redux-Saga 是一个用于处理应用程序的副作用(例如异步调用和访问浏览器缓存的代码)的 redux 中间件。Saga 就是用于管理这些副作用的模块,通过监听 action 并根据需求执行异步调用等操作。
在 Redux-Saga 中,我们可以定义多个 Saga,每个 Saga 都是一个 Generator Function(生成器函数),并且每个 Saga 可以由不同的 effect(影响)构成。Redux-Saga 中存在众多的 effect,例如 put、call、takeLatest 等。
其中,put、call 是在 Saga 函数中最常用的两个 effect。put 用于 dispatch 一个 action,而 call 则用于封装一个异步 API 调用。具体实现如下所示:
// javascriptcn.com 代码示例 import { put, call } from 'redux-saga/effects'; import { fetchUserInfo } from '../api/user'; function* getUserInfoSaga(action) { try { const userInfo = yield call(fetchUserInfo, action.payload); yield put({ type: 'FETCH_USER_SUCCESS', payload: userInfo }); } catch (error) { // 异常处理 } }
Redux-Saga 的使用方法
Redux-Saga 的使用非常简单,只需将其作为 redux 的中间件引入即可。具体实现如下所示:
// javascriptcn.com 代码示例 import createSagaMiddleware from 'redux-saga'; import { applyMiddleware, createStore } from 'redux'; import rootSaga from './sagas'; import rootReducer from './reducers'; const sagaMiddleware = createSagaMiddleware(); const store = createStore(rootReducer, applyMiddleware(sagaMiddleware)); sagaMiddleware.run(rootSaga); export default store;
在上述示例代码中,我们通过 createSagaMiddleware 创建了 Saga 中间件,并在 createStore 中引入了该中间件。最后通过 sagaMiddleware.run() 集中管理所有的 Saga。
Redux-Saga 的示例代码
为了更好地理解 Redux-Saga 的使用,我们将完成一个基于 React 的 TodoList 应用:
1. 建立 todo reducer
// javascriptcn.com 代码示例 const initialState = []; const todoReducer = (state = initialState, action) => { switch (action.type) { case 'FETCH_TODOS_SUCCESS': return action.payload; case 'ADD_TODO_SUCCESS': return [...state, action.payload]; case 'DELETE_TODO_SUCCESS': return state.filter(todo => todo.id !== action.payload); default: return state; } }; export default todoReducer;
2. 建立 todo saga
// javascriptcn.com 代码示例 import { put, call, takeLatest } from 'redux-saga/effects'; import { fetchTodos, addTodo, deleteTodo } from '../api/todo'; function* fetchTodosSaga() { try { const todos = yield call(fetchTodos); yield put({ type: 'FETCH_TODOS_SUCCESS', payload: todos }); } catch (error) { // 异常处理 } } function* addTodoSaga(action) { try { const newTodo = yield call(addTodo, action.payload); yield put({ type: 'ADD_TODO_SUCCESS', payload: newTodo }); } catch (error) { // 异常处理 } } function* deleteTodoSaga(action) { try { yield call(deleteTodo, action.payload); yield put({ type: 'DELETE_TODO_SUCCESS', payload: action.payload }); } catch (error) { // 异常处理 } } function* todoSaga() { yield takeLatest('FETCH_TODOS_REQUEST', fetchTodosSaga); yield takeLatest('ADD_TODO_REQUEST', addTodoSaga); yield takeLatest('DELETE_TODO_REQUEST', deleteTodoSaga); } export default todoSaga;
3. 建立 root saga
import { all } from 'redux-saga/effects'; import todoSaga from './todoSaga'; function* rootSaga() { yield all([todoSaga()]); } export default rootSaga;
4. 建立 UI 组件
// javascriptcn.com 代码示例 import React from 'react'; import { connect } from 'react-redux'; import { fetchTodosRequest, addTodoRequest, deleteTodoRequest } from '../actions/todo'; const TodoList = ({ todos, onAddTodo, onDeleteTodo, onFetchTodos }) => { const newTodoInput = React.createRef(); const handleAddTodo = () => { const title = newTodoInput.current.value; if (title) { onAddTodo({ title }); newTodoInput.current.value = ''; } }; const handleDeleteTodo = id => onDeleteTodo({ id }); React.useEffect(() => { onFetchTodos(); }, [onFetchTodos]); return ( <div> <ul> {todos && todos.map(todo => ( <li key={todo.id}> {todo.title} <button onClick={() => handleDeleteTodo(todo.id)}>删除</button> </li> ))} </ul> <div> <input type="text" ref={newTodoInput} placeholder="请输入新的 todo" /> <button onClick={handleAddTodo}>添加</button> </div> </div> ); }; const mapStateToProps = state => ({ todos: state.todos, }); const mapDispatchToProps = dispatch => ({ onFetchTodos: () => dispatch(fetchTodosRequest()), onAddTodo: payload => dispatch(addTodoRequest(payload)), onDeleteTodo: payload => dispatch(deleteTodoRequest(payload)), }); export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
5. 建立 action 和 API 调用
// javascriptcn.com 代码示例 export const fetchTodosRequest = () => ({ type: 'FETCH_TODOS_REQUEST' }); export const addTodoRequest = payload => ({ type: 'ADD_TODO_REQUEST', payload }); export const deleteTodoRequest = payload => ({ type: 'DELETE_TODO_REQUEST', payload }); export const fetchTodos = async () => { const response = await fetch('https://jsonplaceholder.typicode.com/todos'); return response.json(); }; export const addTodo = async todo => { const response = await fetch('https://jsonplaceholder.typicode.com/todos', { method: 'POST', headers: { 'Content-Type': 'application/json; charset=UTF-8', }, body: JSON.stringify({ ...todo, completed: false }), }); return response.json(); }; export const deleteTodo = async id => { await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`, { method: 'DELETE' }); };
最终,我们成功地创建了一个基于 React 的 TodoList 应用,并通过 Redux-Saga 框架实现了异步调用和副作用控制。
总结
Redux-Saga 是一个非常强大的 redux 中间件,可以用于管理应用程序中的所有副作用。在实际开发中,我们经常需要异步调用 API、访问浏览器缓存等操作,Redux-Saga 就成为了应对这些需求的一个有效解决方案。本篇文章中,我们学习了 Redux-Saga 的基本概念和使用方法,并通过示例代码完成了一个基于 React 的 TodoList 应用。相信大家通过本文的学习已经对 Redux-Saga 的应用有了更深入的理解和掌握。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/654938037d4982a6eb36c7b3