理解React中的Action:状态管理的核心概念

摘要:在React开发中,我们经常听到Action这个词。但Action并不是React自带的特性,而是来自状态管理工具如Redux、Flux、MobX,还有React内置的useReducer Hook。

在React开发中,我们经常听到"Action"这个词。但Action并不是React自带的特性,而是来自状态管理工具如Redux、Flux、MobX,还有React内置的useReducer Hook。


什么是Action?

简单来说,Action就是描述应用中发生了什么事情。它告诉状态管理器:"嘿,这里有个事件发生了,你需要更新状态了"。

Action的核心思想:只说明发生了什么,不关心怎么更新状态。

它是用户意图的声明,比如"用户点击了按钮"或"数据加载完成",作为状态更新的触发信号。


为什么需要Action?

把状态更新写成Action形式有几个好处:

代码更清晰:Action明确表达了发生了什么事件,让代码容易理解
职责分离:组件只管触发Action,不管状态怎么更新。状态更新逻辑集中在Reducer里
方便调试:所有状态变化都由Action触发,可以清楚看到每个Action导致的状态变化
容易测试:生成Action的函数和更新状态的函数都很容易测试
支持中间件:明确的Action机制为添加额外功能提供了基础


Action在不同工具中的实现

Redux中的Action

Redux是最流行的状态管理库之一。

在Redux中:

Action是一个普通对象,必须有type属性

Action Creator是创建Action的函数

用dispatch函数来发送Action

示例代码:

// 定义Action类型
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

// 创建Action的函数
function increment() {
  return {
    type: INCREMENT
  };
}

function decrement(amount) {
  return {
    type: DECREMENT,
    payload: amount
  };
}

// 更新状态的函数
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT:
      return { ...state, count: state.count + 1 };
    case DECREMENT:
      return { ...state, count: state.count - action.payload };
    default:
      return state;
  }
}

// 在组件中使用
import React from 'react';
import { createStore } from 'redux';

const store = createStore(counterReducer);

function Counter() {
  const [count, setCount] = React.useState(store.getState().count);

  React.useEffect(() => {
    const unsubscribe = store.subscribe(() => {
      setCount(store.getState().count);
    });
    return unsubscribe;
  }, []);

  const handleIncrement = () => {
    store.dispatch(increment());
  };

  const handleDecrement = () => {
    store.dispatch(decrement(5));
  };

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={handleIncrement}>增加</button>
      <button onClick={handleDecrement}>减少5</button>
    </div>
  );
}

useReducer中的Action

useReducer是React自带的Hook,用法和Redux很像。

import React, { useReducer } from 'react';

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

const initialState = { count: 0 };
function counterReducer(state, action) {
  switch (action.type) {
    case INCREMENT:
      return { ...state, count: state.count + 1 };
    case DECREMENT:
      return { ...state, count: state.count - action.payload };
    default:
      return state;
  }
}

function CounterWithReducer() {
  const [state, dispatch] = useReducer(counterReducer, initialState);

  const handleIncrement = () => {
    dispatch({ type: INCREMENT });
  };

  const handleDecrement = () => {
    dispatch({ type: DECREMENT, payload: 5 });
  };

  return (
    <div>
      <p>计数: {state.count}</p>
      <button onClick={handleIncrement}>增加</button>
      <button onClick={handleDecrement}>减少5</button>
    </div>
  );
}

MobX中的Action

MobX是响应式状态管理库,用法不太一样。

import React from 'react';
import { makeObservable, observable, action } from 'mobx';
import { observer } from 'mobx-react';

class CounterStore {
  count = 0;

  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action,
      decrement: action
    });
  }

  increment() {
    this.count++;
  }

  decrement(amount) {
    this.count -= amount;
  }
}

const counterStore = new CounterStore();

const MobxCounter = observer(() => {
  const handleIncrement = () => {
    counterStore.increment();
  };

  const handleDecrement = () => {
    counterStore.decrement(5);
  };

  return (
    <div>
      <p>计数: {counterStore.count}</p>
      <button onClick={handleIncrement}>增加</button>
      <button onClick={handleDecrement}>减少5</button>
    </div>
  );
});


处理异步操作

实际开发中经常需要处理异步操作,比如请求数据。

Redux中处理异步

Redux需要用中间件来处理异步,最常用的是redux-thunk。

// 安装:npm install redux-thunk

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

// 异步Action
export const fetchUsers = () => {
  return async (dispatch) => {
    dispatch({ type: 'FETCH_USERS_REQUEST' });
    
    try {
      const response = await fetch('/api/users');
      const users = await response.json();
      dispatch({ type: 'FETCH_USERS_SUCCESS', payload: users });
    } catch (error) {
      dispatch({ type: 'FETCH_USERS_FAILURE', payload: error.message });
    }
  };
};

// 在组件中
function UserList() {
  const dispatch = useDispatch();
  
  useEffect(() => {
    dispatch(fetchUsers());
  }, [dispatch]);
  
  // ... 组件其他代码
}

useReducer中处理异步

useReducer没有中间件,需要在组件内处理异步。

function DataLoader() {
  const [state, dispatch] = useReducer(dataReducer, initialState);
  
  useEffect(() => {
    const loadData = async () => {
      dispatch({ type: 'FETCH_START' });
      
      try {
        const response = await fetch('/api/data');
        const data = await response.json();
        dispatch({ type: 'FETCH_SUCCESS', payload: data });
      } catch (error) {
        dispatch({ type: 'FETCH_ERROR', payload: error.message });
      }
    };
    
    loadData();
  }, []);
  
  // ... 组件其他代码
}


Action的优缺点

优点:

状态变化可预测:知道什么Action会导致什么状态变化

方便调试:可以追踪每个状态变化

职责清晰:组件、Action、Reducer各司其职

容易测试:相关函数都是纯函数,测试简单

团队协作:统一的模式让团队合作更顺畅

缺点:

代码量多:即使是简单功能也要写很多代码

学习成本:需要理解很多新概念

小型项目过重:简单项目用useState就够了

异步处理复杂:需要额外配置


什么时候该用Action?

对于状态复杂、需要多人协作的大型项目,使用Action模式很有帮助。对于状态简单的小项目,直接用React的useState和useContext可能更合适。


总结

Action是React状态管理的核心概念,它把"发生了什么"和"状态怎么更新"分开,让代码更清晰、更易维护。虽然会增加一些代码量,但对于复杂应用来说,这些付出是值得的。

选择使用哪种状态管理方案时,要考虑项目规模、团队习惯和具体需求。理解Action的工作原理,能帮你做出更好的技术选型。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_12981