- ReactJS 菜鸟教程
- ReactJS 教程
- ReactJS - 简介
- ReactJS - 安装
- ReactJS - 特性
- ReactJS - 优点和缺点
- ReactJS - 架构
- ReactJS - 创建 React 应用程序
- ReactJS - JSX
- ReactJS - 组件
- ReactJS - 嵌套组件
- ReactJS - 使用组件
- ReactJS - 组件集合
- ReactJS - 样式
- ReactJS - 属性(props)
- ReactJS - 使用属性创建组件
- ReactJS - props 验证
- ReactJS - 构造函数
- ReactJS - 组件生命周期
- ReactJS - 事件管理
- ReactJS - 创建事件感知组件
- ReactJS - 在Expense Manager APP中引入事件
- ReactJS - 状态管理
- ReactJS - 状态管理 API
- ReactJS - 无状态组件
- ReactJS - 使用 React Hooks 进行状态管理
- ReactJS - 使用 React 钩子的组件生命周期
- ReactJS - 组件的布局
- ReactJS - 分页
- ReactJS - Material 用户界面
- ReactJS - Http 客户端编程
- ReactJS - 表单编程
- ReactJS - 受控组件
- ReactJS - 不受控制的组件
- ReactJS - Formik
- ReactJS - 条件渲染
- ReactJS - 列表
- ReactJS - 键
- ReactJS - 路由
- ReactJS - 冗余
- ReactJS - 动画
- ReactJS - 引导程序
- ReactJS - 地图
- ReactJS - 表格
- ReactJS - 使用 Flux 管理状态
- ReactJS - 测试
- ReactJS - CLI 命令
- ReactJS - 构建和部署
- ReactJS - 示例
- ReactJS - 钩子简介
- ReactJS - 使用 useState
- ReactJS - 使用 useEffect
- ReactJS - 使用 useContext
- ReactJS - 使用 useRef
- ReactJS - 使用 useReducer
- ReactJS - 使用 useCallback
- ReactJS - 使用 useMemo
- ReactJS - 自定义钩子
- ReactJS - 可访问性
- ReactJS - 代码拆分
- ReactJS - 上下文
- ReactJS - 错误边界
- ReactJS - 转发引用
- ReactJS - 片段
- ReactJS - 高阶组件
- ReactJS - 与其他库集成
- ReactJS - 优化性能
- ReactJS - 分析器 API
- ReactJS - 门户
- ReactJS - 没有 ES6 ECMAScript 的 React
- ReactJS - 没有 JSX 的 React
- ReactJS - 协调
- ReactJS - 引用和 DOM
- ReactJS - 渲染属性
- ReactJS - 静态类型检查
- ReactJS - 严格模式
- ReactJS - Web 组件
- ReactJS - 日期选择器
- ReactJS - Helmet
- ReactJS - 内联样式
- ReactJS - 属性类型
- ReactJS - 浏览器路由器
- ReactJS - DOM
- ReactJS - 旋转木马
- ReactJS - 图标
- ReactJS - 表单组件
- ReactJS - 参考 API
ReactJS - State management
我们将执行以下操作来管理我们的 redux store。
- 通过 async fetch api 从服务器获取费用,并在 Redux store 中设置。
- 通过异步 fetch 编程向服务器添加新费用,并在 Redux store 中设置添加新费用。
- 通过 async fetch api 从服务器中删除现有费用并更新 Redux store。
让我们创建 action types、action creator、actions 和 reducer 来管理 Redux state。
在 src folder 下创建文件夹 actions。
接下来,创建一个文件,types.js创建操作类型。
export const LIST_EXPENSE_STARTED = 'LIST_EXPENSE_STARTED';
export const LIST_EXPENSE_SUCCESS = 'LIST_EXPENSE_SUCCESS';
export const LIST_EXPENSE_FAILURE = 'LIST_EXPENSE_FAILURE';
export const ADD_EXPENSE_STARTED = 'ADD_EXPENSE_STARTED';
export const ADD_EXPENSE_SUCCESS = 'ADD_EXPENSE_SUCCESS';
export const ADD_EXPENSE_FAILURE = 'ADD_EXPENSE_FAILURE';
export const DELETE_EXPENSE_STARTED = 'DELETE_EXPENSE_STARTED';
export const DELETE_EXPENSE_SUCCESS = 'DELETE_EXPENSE_SUCCESS';
export const DELETE_EXPENSE_FAILURE = 'DELETE_EXPENSE_FAILURE';
接下来,创建一个文件,index.js actions folder 下创建操作创建者。
import {
LIST_EXPENSE_STARTED, LIST_EXPENSE_SUCCESS, LIST_EXPENSE_FAILURE,
ADD_EXPENSE_STARTED, ADD_EXPENSE_SUCCESS, ADD_EXPENSE_FAILURE,
DELETE_EXPENSE_STARTED, DELETE_EXPENSE_SUCCESS, DELETE_EXPENSE_FAILURE,
} from "./types";
export const getExpenseListStarted = () => {
return {
type: LIST_EXPENSE_STARTED
}
}
export const getExpenseListSuccess = data => {
return {
type: LIST_EXPENSE_SUCCESS,
payload: {
data
}
}
}
export const getExpenseListFailure = error => {
return {
type: LIST_EXPENSE_FAILURE,
payload: {
error
}
}
}
export const addExpenseStarted = () => {
return {
type: ADD_EXPENSE_STARTED
}
}
export const addExpenseSuccess = data => {
return {
type: ADD_EXPENSE_SUCCESS,
payload: {
data
}
}
}
export const addExpenseFailure = error => {
return {
type: ADD_EXPENSE_FAILURE,
payload: {
error
}
}
}
export const deleteExpenseStarted = () => {
return {
type: DELETE_EXPENSE_STARTED
}
}
export const deleteExpenseSuccess = data => {
return {
type: DELETE_EXPENSE_SUCCESS,
payload: {
data
}
}
}
export const deleteExpenseFailure = error => {
return {
type: DELETE_EXPENSE_FAILURE,
payload: {
error
}
}
}
在这里,我们为 fetch api 的每个可能结果(成功、失败和错误)创建了一个操作创建器。由于我们将使用 3 个 Web API 调用,并且每个调用将有三种可能的结果,因此我们使用 9 个 action creator。
接下来,创建一个文件,expenseActions.js actions folder 下,并创建三个函数来获取、添加和删除费用以及分派状态更改。
import {
getExpenseListStarted, getExpenseListSuccess, getExpenseListFailure,
addExpenseStarted, addExpenseSuccess, addExpenseFailure,
deleteExpenseStarted, deleteExpenseSuccess, deleteExpenseFailure
} from "./index";
export const getExpenseList = () => async dispatch => {
dispatch(getExpenseListStarted());
try {
const res = await fetch('http://localhost:8000/api/expenses');
const data = await res.json();
var items = [];
data.forEach((item) => {
let newItem = {
id: item._id,
name: item.name,
amount: item.amount,
spendDate: item.spend_date,
category: item.category
}
items.push(newItem)
});
dispatch(getExpenseListSuccess(items));
} catch (err) {
dispatch(getExpenseListFailure(err.message));
}
}
export const addExpense = (data) => async dispatch => {
dispatch(addExpenseStarted());
let newItem = {
name: data.name,
amount: data.amount,
spend_date: data.spendDate,
category: data.category
}
console.log(newItem);
try {
const res = await fetch('http://localhost:8000/api/expense', {
method: 'POST',
body: JSON.stringify(newItem),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
});
const data = await res.json();
newItem.id = data._id;
dispatch(addExpenseSuccess(newItem));
} catch (err) {
console.log(err);
dispatch(addExpenseFailure(err.message));
}
}
export const deleteExpense = (id) => async dispatch => {
dispatch(deleteExpenseStarted());
try {
const res = await fetch('http://localhost:8000/api/expense/' + id, {
method: 'DELETE'
});
const data = await res.json();
dispatch(deleteExpenseSuccess(id));
} catch (err) {
dispatch(deleteExpenseFailure(err.message));
}
}
这里
- 使用异步获取 api 进行 Web API 调用。
- 使用 dispatch 函数在成功、失败和错误事件期间调度适当的 action。
创建一个文件夹,在 src 文件夹下创建一个 reducers 并创建一个文件,index.js reducers 文件夹下创建 Redux Reducers。
import {
LIST_EXPENSE_STARTED, LIST_EXPENSE_SUCCESS, LIST_EXPENSE_FAILURE,
ADD_EXPENSE_STARTED, ADD_EXPENSE_SUCCESS, ADD_EXPENSE_FAILURE,
DELETE_EXPENSE_STARTED, DELETE_EXPENSE_SUCCESS, DELETE_EXPENSE_FAILURE
} from "../actions/types";
// define initial state of user
const initialState = {
data: null,
loading: false,
error: null
}
export default function expenseReducer(state = initialState, action) {
switch (action.type) {
case LIST_EXPENSE_STARTED:
return {
...state,
loading: true
}
case LIST_EXPENSE_SUCCESS:
const { data } = action.payload;
return {
...state,
data,
loading: false
}
case LIST_EXPENSE_FAILURE:
const { error } = action.payload;
return {
...state,
error
}
case ADD_EXPENSE_STARTED:
return {
...state,
loading: true
}
case ADD_EXPENSE_SUCCESS:
return {
...state,
loading: false
}
case ADD_EXPENSE_FAILURE:
const { expenseError } = action.payload;
return {
...state,
expenseError
}
case DELETE_EXPENSE_STARTED:
return {
...state,
loading: true
}
case DELETE_EXPENSE_SUCCESS:
return {
...state,
data: state.data.filter(expense => expense.id !== action.payload.data),
loading: false
}
case DELETE_EXPENSE_FAILURE:
const { deleteError } = action.payload;
return {
...state,
deleteError
}
default:
return state
}
}
在这里,我们更新了每种 action 类型的 redux store state。
接下来,在 src 文件夹下打开index.js文件并包含 Provider 组件,以便所有组件都可以连接并使用 redux store。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import rootReducer from './reducers';
import App from './components/App';
const store = createStore(rootReducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
这里
- 导入 createStore 和 applyMiddleware
- 从 redux-thunk 库导入 thunk(用于异步获取 api)
- 从 redux 库导入的 Provider
- 通过配置 reducer 和 thunk middleware 使用 createStore 创建 newstore
- 将 Provider 组件作为顶级组件附加到 redux store