我们将执行以下操作来管理我们的 redux 存储。
- 通过 async fetch api 从服务器获取费用并将其设置在 Redux 存储中。
- 通过异步获取编程向服务器添加新费用,并设置在 Redux 存储中添加新费用。
- 通过 async fetch api 从服务器中删除现有费用并更新 Redux 存储。
让我们创建用于管理 Redux 状态的操作类型、操作创建者、操作和归约器。
在 src 文件夹下创建文件夹操作。
接下来,创建一个文件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 文件夹下创建一个文件 feeActions.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)); } }
这里,
- 使用 async fetch 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"; // 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 } }
在这里,我们更新了每种操作类型的 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 创建 newstore
- 将 Provider 组件附加为带有 redux 存储的顶级组件