4

我构建了小型预算计算器,这是我第一次使用 redux-toolkit,问题是如何在 redux-toolkit 中的 reducer 之间共享/传递状态?(如何使用余额切片中的totalIncomes和totalExpenses来计算总余额?

另一个问题是可以使用 redux-toolkit 而不是普通的 redux

收入.js:

const incomesSlice = createSlice({
  name: "incomes",
  initialState: {
    list: [],
    loading: false,
    totalIncomes: 0,
    lastFetch: null,
  },
  reducers: {
    ADD_INCOME: (state, action) => {
      state.list.push({
        id: uuidv4(),
        description: action.payload.description,
        amount: action.payload.amount,
      });
    },
    REMOVE_INCOME: (state, action) => {
      const index = state.list.findIndex(
        (income) => income.id === action.payload.id
      );
      state.list.splice(index, 1);
    },
    TOTAL_INCOMES: (state, action) => {
      state.totalIncomes = state.list.reduce(
        (acc, curr) => acc + curr.amount,
        0
      );
    },
  },
});

费用.js:

const expensesSlice = createSlice({
  name: "expenses",
  initialState: {
    list: [],
    loading: false,
    totalExpenses: 0,
    lastFetch: null,
  },
  reducers: {
    ADD_EXPENSE: (state, action) => {
      state.list.push({
        id: uuidv4(),
        description: action.payload.description,
        amount: action.payload.amount,
      });
    },
    REMOVE_EXPENSE: (state, action) => {
      const index = state.list.findIndex(
        (expense) => expense.id === action.payload.id
      );
      state.list.splice(index, 1);
    },
    TOTAL_EXPENSES: (state, action) => {
      state.totalExpenses = state.list.reduce(
        (acc, curr) => acc + curr.amount,
        0
      );
    },
  },
});

export const {
  ADD_EXPENSE,
  REMOVE_EXPENSE,
  TOTAL_EXPENSES,
} = expensesSlice.actions;
export default expensesSlice.reducer;

平衡.js:

const balanceSlice = createSlice({
  name: "balance",
  initialState: {
    total: 0
  },
  reducers: {
    CALC_TOTAL: (state, action) => {
      // How to Calculate this ?
    },
  },
});enter code here

export const { CALC_TOTAL } = balanceSlice.actions;
export default balanceSlice.reducer;
4

2 回答 2

6

对于任何研究这一点的人 - 作者是使用 redux 进行状态管理的错误方法。

使用 redux 时,您希望您的状态尽可能标准化 - 您不应存储不需要/重复的状态或可以根据其他状态计算的状态,在此示例中,无需保存 totalIncomes,因为我们可以根据列表进行计算收入(总费用和余额也是如此)。

如前所述,totalIncomes 不应该是状态的一部分,而应该是计算值,您可以即时计算它或使用选择器。在下面的示例中,我将使用选择器。

Redux 工具包解决方案

要将它与 Redux 工具包一起使用,它可能看起来像这样,我删除了部分代码以用于 brewity:

收入切片

// ...

const incomesSlice = createSlice({
  name: "incomes",
  initialState: {
    list: [],
  },
  reducers: {
    ADD_INCOME: (state, action) => {
      state.list.push({
        id: uuidv4(),
        description: action.payload.description,
        amount: action.payload.amount,
      });
    },
    REMOVE_INCOME: (state, action) => {
      const index = state.list.findIndex(
        (income) => income.id === action.payload.id
      );
      state.list.splice(index, 1);
    },
  },
});


export const getTotalIncome = createSelector(
    totalIncomeSelector,
    calculateTotalIncome,
);

export function totalIncomeSelector(state) {
    return state.incomes.list;
}

export function calculateTotalIncome(incomesList) {
    return incomesList.reduce((total, income) => total + income.amount);    
}

export const {
    ADD_INVOICE,
    REMOVE_INVOICE,
} = incomesSlice.actions;

export default incomesSlice.reducer;

费用切片 - 为酿造而移除的部分

// ...

const expensesSlice = createSlice({
  name: "expenses",
  initialState: {
    list: [],
  },
  reducers: {
    ADD_EXPENSE: (state, action) => {
      state.list.push({
        id: uuidv4(),
        description: action.payload.description,
        amount: action.payload.amount,
      });
    },
    REMOVE_EXPENSE: (state, action) => {
      const index = state.list.findIndex(
        (income) => income.id === action.payload.id
      );
      state.list.splice(index, 1);
    },
  },
});


export const getTotalExpense = createSelector(
    totalExpenseSelector,
    calculateTotalExpense,
);

export function totalExpenseSelector(state) {
    return state.expenses.list;
}

export function calculateTotalExpenseexpenseList) {
    return expensesList.reduce((total, expense) => total + expense.amount); 
}

export const {
    ADD_EXPENSE,
    REMOVE_EXPENSE,
} = expensesSlice.actions;

export default expensesSlice.reducer;

平衡切片 - 你真的不需要切片,你只需要一个选择器

import { getTotalIncome, totalIncomeSelector } from './incomeSlice';
import { getTotalExpense, totalExpenseSelector } from './expenseSlice';

export const getBalance = createSelector(
    getTotalIncome,
    getTotalExpense,
    (totalIncome, totalExpense) => totalIncome - totalIncome,
);


示例组件

// ...

function BalanceComponent({
    totalIncome,
    totalExpense,
    balance,
}) {
    return (
        <div>
            <h1>Finance overview</h1>
            <div>
                <span>Total Income:</span>
                <span>{totalIncome}</span>
            </div>
            <div>
                <span>Total Expense:</span>
                <span>{totalExpense}</span>
            </div>
            <div>
                <span>Balance:</span>
                <span>{balance}</span>
            </div>
        </div>
    );
}

function mapStateToProps(state) {
    return {
        totalIncome: getTotalIncome(state),
        totalExpense: getTotalExpense(state),
        balance: getBalance(state),
    }
}

export default connect(mapStateToProps)(BalanceComponent);

注意:在这个问题中,作者似乎将他的状态分成了太多的切片,所有这一切都可以通过将它们全部作为一个切片来简单得多。这就是我会做的。

于 2020-08-18T08:35:32.627 回答
1

使用 redux-toolkit 代替普通的 redux 可以吗

的。它最初是为了帮助解决有关 Redux 的常见问题而创建的。见其目的

如何在减速器之间共享/传递状态redux-toolkit

  1. 您可以将使用过的状态部分传递给action.payload.
dispatch(CALC_TOTAL(totalIncomes,totalExpenses))
  1. 您可以使用extraReducers并“聆听”您的收入/支出变化。

  2. 您可以创建一个中间件或使用createAsyncThunk可以引用最新状态的getState().

于 2020-04-21T11:17:41.303 回答