ReactJS 教程

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 事件 ReactJS 状态管理 ReactJS 状态管理 API ReactJS 无状态组件 ReactJS Hooks 进行状态管理 ReactJS Hooks 的组件生命周期 ReactJS 布局组件 ReactJS 分页 ReactJS Material UI ReactJS Http 客户端编程 ReactJS 表单编程 ReactJS 受控组件 ReactJS 非受控组件 ReactJS Formik ReactJS 条件渲染 ReactJS 列表 ReactJS Key 键 ReactJS 路由 ReactJS Redux ReactJS 动画 ReactJS Bootstrap ReactJS Map ReactJS 表格 ReactJS 使用 Flux 管理状态 ReactJS 测试 ReactJS CLI 命令 ReactJS 构建和部署 ReactJS 示例

Hooks

ReactJS Hooks 简介 ReactJS 使用 useState ReactJS 使用 useEffect ReactJS 使用 useContext ReactJS 使用 useRef ReactJS 使用 useReducer ReactJS 使用 useCallback ReactJS 使用 useMemo ReactJS 自定义 Hooks

ReactJS 高级

ReactJS 可访问性 ReactJS 代码拆分 ReactJS 上下文 ReactJS 错误边界 ReactJS 转发 Refs ReactJS 片段 ReactJS 高阶组件 ReactJS 与其他库集成 ReactJS 优化性能 ReactJS Profiler API ReactJS Portals ReactJS 不使用 ES6 ECMAScript ReactJS 不使用 JSX 的 React ReactJS Reconciliation ReactJS Refs 和 DOM ReactJS 渲染道具 ReactJS 静态类型检查 ReactJS 严格模式 ReactJS Web 组件

其他概念

ReactJS 日期选择器 ReactJS Helmet ReactJS 内联样式 ReactJS PropTypes ReactJS BrowserRouter ReactJS DOM ReactJS 轮播 ReactJS 图标 ReactJS 表单组件 ReactJS 参考 API

ReactJS 有用资源

ReactJS 快速指南 ReactJS 备忘录 Axios 备忘录 ReactJS 有用资源 ReactJS 讨论


ReactJS - 状态管理

我们将执行以下操作来管理我们的 redux 存储。

  • 通过异步获取 api 从服务器获取费用并将其设置在 Redux 存储中。

  • 通过异步获取编程将新费用添加到服务器,并在 Redux 存储中添加新费用。

  • 通过异步获取 api 从服务器删除现有费用并更新 Redux 存储。

让我们创建操作类型、操作创建器、操作和 Reducer 来管理 Redux 状态。

在 src 文件夹下创建一个文件夹 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';

接下来,在actions文件夹下创建一个文件index.js来创建动作创建器。

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 的每种可能结果(成功、失败和错误)创建了一个动作创建器。由于我们将使用三个 web api 调用,并且每个调用将有三种可能的结果,因此我们使用了 9 个动作创建器。

接下来,在actions文件夹下创建一个文件expenseActions.js,并创建三个函数来获取、添加和删除费用并分派状态更改。

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 调用。

  • 使用调度函数在成功、失败和错误事件期间调度适当的操作。

在 src 文件夹下创建一个文件夹 reducers,并在 reducers 文件夹下创建一个文件 index.js 来创建 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";

// 定义用户的初始状态
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
   }
}

在这里,我们更新了每种操作类型的 redux 存储状态。

接下来,打开 src 文件夹下的 index.js 文件并包含 Provider 组件,以便所有组件都可以连接并使用 redux 存储。

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 中间件使用 createStore 创建新存储
  • 将 Provider 组件作为顶级组件与 redux store 连接起来

reactjs_example.html