异步 Action 和异步 Reducer 在 Redux 中的应用实践

前言

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


纠错
反馈