前言
Redux 是一个非常流行的 JavaScript 应用程序状态管理库,它提供了一种可预测性的数据流模式,使得应用程序状态的管理变得更加容易。Redux 中的 Action 和 Reducer 是两个非常重要的概念,它们用于描述应用程序状态的变化。在本文中,我们将讨论异步 Action 和异步 Reducer 在 Redux 中的应用实践。
Redux 中的 Action 和 Reducer
在 Redux 中,Action 是一个简单的 JavaScript 对象,它描述了应用程序状态的变化。Action 包含一个 type 属性,用于描述 Action 的类型,以及一个 payload 属性,用于描述 Action 的数据。例如,下面是一个简单的 Action:
{ type: 'ADD_TODO', payload: { id: 1, text: 'Learn Redux' } }
Reducer 是一个纯函数,它接收当前的状态和一个 Action,返回一个新的状态。Reducer 的作用是根据 Action 的类型,更新应用程序的状态。例如,下面是一个简单的 Reducer:
function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return [ ...state, action.payload ]; default: return state; } }
在上面的例子中,todos 函数是一个 Reducer,它接收一个 state 参数和一个 action 参数,返回一个新的状态。当 Action 的类型为 ADD_TODO 时,todos 函数会将 action.payload 添加到 state 中,并返回一个新的状态。
异步 Action
异步 Action 是指在处理 Action 时需要进行异步操作的 Action。例如,当我们需要从服务器获取数据时,需要进行异步操作。在 Redux 中,我们可以使用 Redux-thunk 或 Redux-saga 等中间件来处理异步 Action。
Redux-thunk
Redux-thunk 是一个 Redux 中间件,它允许我们在 Action 中返回一个函数。这个函数可以接收 dispatch 和 getState 函数作为参数,从而让我们可以在 Action 中进行异步操作。例如,下面是一个使用 Redux-thunk 处理异步 Action 的例子:
function fetchTodos() { return dispatch => { dispatch({ type: 'FETCH_TODOS_REQUEST' }); fetch('/api/todos') .then(response => response.json()) .then(todos => dispatch({ type: 'FETCH_TODOS_SUCCESS', payload: todos })) .catch(error => dispatch({ type: 'FETCH_TODOS_FAILURE', payload: error })); }; }
在上面的例子中,fetchTodos 函数返回一个函数,这个函数接收 dispatch 函数作为参数。在返回的函数中,我们首先 dispatch 一个 FETCH_TODOS_REQUEST Action,表示我们开始获取数据。然后,我们使用 fetch 函数从服务器获取数据,当数据返回时,我们再 dispatch 一个 FETCH_TODOS_SUCCESS Action,将数据作为 payload 传递。如果出现错误,我们会 dispatch 一个 FETCH_TODOS_FAILURE Action,将错误信息作为 payload 传递。
Redux-saga
Redux-saga 是一个 Redux 中间件,它使用 ES6 的 Generator 函数来处理异步操作。使用 Redux-saga 可以让我们更加清晰地描述异步操作的流程。例如,下面是一个使用 Redux-saga 处理异步 Action 的例子:
import { put, takeLatest, all } from 'redux-saga/effects'; function* fetchTodos() { try { const todos = yield fetch('/api/todos').then(response => response.json()); yield put({ type: 'FETCH_TODOS_SUCCESS', payload: todos }); } catch (error) { yield put({ type: 'FETCH_TODOS_FAILURE', payload: error }); } } function* watchFetchTodos() { yield takeLatest('FETCH_TODOS_REQUEST', fetchTodos); } export default function* rootSaga() { yield all([ watchFetchTodos() ]); }
在上面的例子中,我们首先定义了一个 fetchTodos Generator 函数,它使用 yield 关键字来控制异步操作的流程。当我们 dispatch 一个 FETCH_TODOS_REQUEST Action 时,watchFetchTodos 函数会调用 fetchTodos 函数来处理这个 Action。当数据返回时,我们 dispatch 一个 FETCH_TODOS_SUCCESS Action,将数据作为 payload 传递。如果出现错误,我们会 dispatch 一个 FETCH_TODOS_FAILURE Action,将错误信息作为 payload 传递。
异步 Reducer
异步 Reducer 是指在处理 Reducer 时需要进行异步操作的 Reducer。例如,当我们需要从服务器获取数据时,需要进行异步操作。在 Redux 中,我们可以使用 Redux-thunk 或 Redux-saga 等中间件来处理异步 Reducer。
Redux-thunk
使用 Redux-thunk 处理异步 Reducer 的方法与处理异步 Action 的方法类似。我们可以在 Reducer 中返回一个函数,这个函数可以接收 dispatch 和 getState 函数作为参数,并且可以进行异步操作。例如,下面是一个使用 Redux-thunk 处理异步 Reducer 的例子:
function todos(state = { loading: false, data: [] }, action) { switch (action.type) { case 'FETCH_TODOS_REQUEST': return { ...state, loading: true }; case 'FETCH_TODOS_SUCCESS': return { ...state, loading: false, data: action.payload }; case 'FETCH_TODOS_FAILURE': return { ...state, loading: false, error: action.payload }; default: return state; } } function fetchTodos() { return dispatch => { dispatch({ type: 'FETCH_TODOS_REQUEST' }); fetch('/api/todos') .then(response => response.json()) .then(todos => dispatch({ type: 'FETCH_TODOS_SUCCESS', payload: todos })) .catch(error => dispatch({ type: 'FETCH_TODOS_FAILURE', payload: error })); }; }
在上面的例子中,我们定义了一个 todos Reducer,它接收一个 state 参数和一个 action 参数,并返回一个新的状态。当 Action 的类型为 FETCH_TODOS_REQUEST 时,todos 函数会将 loading 属性设置为 true。当 Action 的类型为 FETCH_TODOS_SUCCESS 时,todos 函数会将 loading 属性设置为 false,并将数据添加到 data 属性中。当 Action 的类型为 FETCH_TODOS_FAILURE 时,todos 函数会将 loading 属性设置为 false,并将错误信息添加到 error 属性中。我们还定义了一个 fetchTodos 函数,它返回一个函数,这个函数接收 dispatch 函数作为参数。在返回的函数中,我们首先 dispatch 一个 FETCH_TODOS_REQUEST Action,表示我们开始获取数据。然后,我们使用 fetch 函数从服务器获取数据,当数据返回时,我们再 dispatch 一个 FETCH_TODOS_SUCCESS Action,将数据作为 payload 传递。如果出现错误,我们会 dispatch 一个 FETCH_TODOS_FAILURE Action,将错误信息作为 payload 传递。
Redux-saga
使用 Redux-saga 处理异步 Reducer 的方法与处理异步 Action 的方法类似。我们可以使用 Generator 函数来控制异步操作的流程。例如,下面是一个使用 Redux-saga 处理异步 Reducer 的例子:
import { put, takeLatest, all } from 'redux-saga/effects'; function* fetchTodos() { try { const todos = yield fetch('/api/todos').then(response => response.json()); yield put({ type: 'FETCH_TODOS_SUCCESS', payload: todos }); } catch (error) { yield put({ type: 'FETCH_TODOS_FAILURE', payload: error }); } } function* watchFetchTodos() { yield takeLatest('FETCH_TODOS_REQUEST', fetchTodos); } function* todos() { yield all([ watchFetchTodos() ]); } export default todos;
在上面的例子中,我们定义了一个 fetchTodos Generator 函数,它使用 yield 关键字来控制异步操作的流程。当我们 dispatch 一个 FETCH_TODOS_REQUEST Action 时,watchFetchTodos 函数会调用 fetchTodos 函数来处理这个 Action。当数据返回时,我们 dispatch 一个 FETCH_TODOS_SUCCESS Action,将数据作为 payload 传递。如果出现错误,我们会 dispatch 一个 FETCH_TODOS_FAILURE Action,将错误信息作为 payload 传递。我们还定义了一个 todos 函数,它使用 all 函数来组合多个 Generator 函数。
总结
在 Redux 中,异步 Action 和异步 Reducer 是非常重要的概念。使用 Redux-thunk 或 Redux-saga 等中间件可以让我们更加方便地处理异步操作。在编写应用程序时,我们应该根据具体情况选择合适的中间件,并且尽量避免过多地使用异步操作,以免增加代码的复杂度。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658cf695eb4cecbf2d2da045