在react开发中,我们经常听到"Action"这个词。但Action并不是React自带的特性,而是来自状态管理工具如Redux、Flux、MobX,还有React内置的useReducer Hook。
简单来说,Action就是描述应用中发生了什么事情。它告诉状态管理器:"嘿,这里有个事件发生了,你需要更新状态了"。
Action的核心思想:只说明发生了什么,不关心怎么更新状态。
它是用户意图的声明,比如"用户点击了按钮"或"数据加载完成",作为状态更新的触发信号。
把状态更新写成Action形式有几个好处:
代码更清晰:Action明确表达了发生了什么事件,让代码容易理解
职责分离:组件只管触发Action,不管状态怎么更新。状态更新逻辑集中在Reducer里
方便调试:所有状态变化都由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、Reducer各司其职
容易测试:相关函数都是纯函数,测试简单
团队协作:统一的模式让团队合作更顺畅
缺点:
代码量多:即使是简单功能也要写很多代码
学习成本:需要理解很多新概念
小型项目过重:简单项目用useState就够了
异步处理复杂:需要额外配置
对于状态复杂、需要多人协作的大型项目,使用Action模式很有帮助。对于状态简单的小项目,直接用React的useState和useContext可能更合适。
Action是React状态管理的核心概念,它把"发生了什么"和"状态怎么更新"分开,让代码更清晰、更易维护。虽然会增加一些代码量,但对于复杂应用来说,这些付出是值得的。
选择使用哪种状态管理方案时,要考虑项目规模、团队习惯和具体需求。理解Action的工作原理,能帮你做出更好的技术选型。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
如今的 Web 前端已被 React、Vue 和 Angular 三分天下,尽管现在的 jQuery 已不再那么流行,但 jQuery 的设计思想还是非常值得致敬和学习的,特别是 jQuery 的插件化。
受控组件与非受控组件在官网与国内网上的资料都不多,有些人觉得它可有可不有,也不在意。这恰恰显示React的威力,满足不同规模大小的工程需求。
一般在传统模式下,我们构建前端项目很简单。就是下载各种js文件,如JQuery、Echart等,直接放置在html静态文件。Webpack则是JavaScript中比较知名的打包工具。这两个构建工具构成了React应用快速搭建的基础。
Gatsby能快速的使用 React 生态系统来生成静态网站,可以结合React Component、Markdown 和服务端渲染来完成静态网站生成让他更强大。
React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归;具体的三种方式:函数式定义的无状态组件、es5原生方式React.createClass定义的组件、es6形式的extends React.Component定义的组件
React主要思想是通过构建可复用组件来构建用户界面,每个组件都有自己的生命周期,它规定了组件的状态和方法需要在哪个阶段改变和执行。所谓组件就是有限状态机,,表示有限个状态以及在这些状态之间的转移和动作行为的模型。
React 相关的优化:使用 babel-react-optimize 对 React 代码进行优化,检查没有使用的库,去除 import 引用,按需打包所用的类库,比如 lodash 、echarts 等.Webpack 构建打包存在的问题两个方面:构建速度慢,打包后的文件体积过大
这篇文章主要介绍React Router定义路由之后如何传值,有关React和React Router 。react router中页面传值的三种方法:props.params、query、state
react 高阶组件简单的理解是:一个包装了另一个基础组件的组件。高阶组件的两种形式:属性代理(Props Proxy)、反向继承 (Inheritance Inversion)
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!