博主头像
<CodeEra />

心存敬畏 行有所止

Redux 工程化:Action Creator 的创建

基本概念

Action Creator 是一个函数,它创建并返回一个 action 对象。使用 Action Creator 可以带来以下好处:

  • 集中管理 action 类型
  • 减少手动编写 action 对象时的错误
  • 便于处理异步操作
  • 提高代码可维护性

基础 Action Creator

// 基础形式
function addTodo(text) {
  return {
    type: 'ADD_TODO',
    payload: {
      text,
      id: Date.now(),
      completed: false
    }
  };
}

工程化实践

1. 常量管理 Action 类型

// actionTypes.js
export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO';
export const DELETE_TODO = 'DELETE_TODO';

// actions.js
import { ADD_TODO, TOGGLE_TODO, DELETE_TODO } from './actionTypes';

export const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { text, id: Date.now(), completed: false }
});

export const toggleTodo = (id) => ({
  type: TOGGLE_TODO,
  payload: { id }
});

export const deleteTodo = (id) => ({
  type: DELETE_TODO,
  payload: { id }
});

2. 使用 payload 规范

推荐使用 Flux Standard Action (FSA) 规范:

  • type: 必须的字符串
  • payload: 可选的数据
  • error: 可选的布尔值,表示是否是错误
  • meta: 可选的额外信息

3. 异步 Action Creator

对于异步操作,可以使用 Redux Thunk 或 Redux Saga 等中间件:

// 使用 Redux Thunk
export const fetchTodos = () => {
  return async (dispatch) => {
    dispatch({ type: 'FETCH_TODOS_REQUEST' });
    
    try {
      const response = await api.getTodos();
      dispatch({
        type: 'FETCH_TODOS_SUCCESS',
        payload: response.data
      });
    } catch (error) {
      dispatch({
        type: 'FETCH_TODOS_FAILURE',
        payload: error,
        error: true
      });
    }
  };
};

4. Action Creator 工厂函数

对于相似的 action,可以创建工厂函数:

const createAsyncActions = (type) => {
  return {
    request: (payload) => ({ type: `${type}_REQUEST`, payload }),
    success: (payload) => ({ type: `${type}_SUCCESS`, payload }),
    failure: (error) => ({ type: `${type}_FAILURE`, payload: error, error: true })
  };
};

// 使用
const todoActions = createAsyncActions('TODO');
// todoActions.request(), todoActions.success(), todoActions.failure()

5. 使用 redux-actions 库

redux-actions 提供了 createActionhandleActions 等实用函数:

import { createAction } from 'redux-actions';

export const addTodo = createAction('ADD_TODO', text => ({
  text,
  id: Date.now(),
  completed: false
}));

// 使用
dispatch(addTodo('Learn Redux'));

最佳实践

  1. 命名规范:使用全大写和下划线命名 action 类型,如 FETCH_USER_SUCCESS
  2. 单一职责:每个 action creator 只做一件事
  3. 纯函数:确保 action creator 是纯函数,不产生副作用
  4. 文档注释:为每个 action creator 添加清晰的注释
  5. 测试:为 action creator 编写单元测试

目录结构建议

store/
  actions/
    index.js          // 导出所有 action creator
    todoAction.js    // todo 相关的 action
    userAction.js    // 用户相关的 action
  reducers/
    index.js          
    todoReducer.js    // todo 相关的 action
    userReducer.js    // 用户相关的 action
  actionTypes.js    // 所有 action 类型常量
  index.js

命名导出及使用方式

// actions/index.js

// 从各个模块导入 action creators
import * as todoActions from './todoActions';
import * as userActions from './userActions';
import * as productActions from './productActions';

// 集中导出所有 action creators
export {
  todoActions,
  userActions,
  productActions
};

// 也可以选择平铺导出(根据项目规模决定)
export * from './todoActions';
export * from './userActions';
export * from './productActions';

// 在组件中使用------------------------------------

// 使用命名空间方式
import { todoActions, userActions } from '../actions';

dispatch(todoActions.addTodo('Learn Redux'));
dispatch(userActions.login({ username: 'test', password: '123' }));

// 使用平铺导出方式
import { addTodo, login } from '../actions';

dispatch(addTodo('Learn Redux'));
dispatch(login({ username: 'test', password: '123' }));
发表新评论