redux-toolkit在reducer之间的共享状态

时间:2020-04-21 10:55:22

标签: reactjs redux redux-toolkit

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

另一个问题是可以使用redux-toolkit代替纯redux

incomes.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
      );
    },
  },
});

expenses.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;

balance.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;

2 个答案:

答案 0 :(得分:3)

对于任何对此感兴趣的人-使用Redux进行状态管理都是错误的方法。

使用redux时,您希望状态尽可能地规范化-您不应该存储未使用/重复的状态或可以基于其他状态计算的状态,在此示例中,无需保存totalIncomes,因为我们可以基于在收入列表上(totalExpenses和余额相同)。

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

Redux Toolkit解决方案

要在Redux工具包中使用它,它可能看起来像这样,我已删除了部分代码以提高可酿酒性:

收入切片

// ...

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);

注意:在这个问题中,作者似乎将自己的状态分解为多个切片,将这些全部作为一个切片可以简化很多。那就是我要做的。

答案 1 :(得分:1)

可以使用redux-toolkit代替纯redux

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

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

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

  2. 您可以创建中间件或使用createAsyncThunk,在其中可以使用getState()引用最新状态。