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

更新日期: 2025-10-11 阅读: 297 标签: React

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://fly63.com/article/detial/12981

相关推荐

Gatsby.js_一款基于React.js静态站点生成工具

Gatsby能快速的使用 React 生态系统来生成静态网站,可以结合React Component、Markdown 和服务端渲染来完成静态网站生成让他更强大。

解决vscode 开发react 导入绝对路径 无法跳转的问题

相对路径可正常跳转,但是在webpack配置alias使用绝对路径后无法跳转.解决办法:需要添加一个jsconfig文件,如下:

react router中页面传值的三种方法

这篇文章主要介绍React Router定义路由之后如何传值,有关React和React Router 。react router中页面传值的三种方法:props.params、query、state

React常用hook的优化useEffect浅比较

先说说react原版的useEffect使用起来不便的地方,这里的effect每次更新都会执行,因为第三个参数一直是不等的,第二是在deps依赖很多的时候是真的麻烦

React 监听页面滚动,界面动态显示

当页面滚动时,如何动态切换布局/样式, 添加滚动事件的监听/注销

React + Webpack 构建打包优化

React 相关的优化:使用 babel-react-optimize 对 React 代码进行优化,检查没有使用的库,去除 import 引用,按需打包所用的类库,比如 lodash 、echarts 等.Webpack 构建打包存在的问题两个方面:构建速度慢,打包后的文件体积过大

react-router v4 按需加载的配置方法

在react项目开发中,当访问默认页面时会一次性请求所有的js资源,这会大大影响页面的加载速度和用户体验。所以添加按需加载功能是必要的,以下是配置按需加载的方法

React事件处理函数必须使用bind(this)的原因

学习React的过程中发现调用函数的时候必须使用bind(this),之后直接在class中声明函数即可正常使用,但是为什么呢,博主进行了一番查阅,总结如下。

grpc-web与react的集成

使用create-react-app脚手架生成react相关部分,脚手架内部会通过node自动起一个客户端,然后和普通的ajax请求一样,和远端服务器进行通信,只不过这里采用支持rpc通信的grpc-web来发起请求,远端采用docker容器的node服务器,node服务器端使用envoy作为代理

react中的refs属性的使用方法

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!