【问题标题】:redux-toolkit sharing state between reducerredux-toolkit 在 reducer 之间共享状态
【发布时间】:2020-08-04 02:23:37
【问题描述】:

我正在构建小型预算计算器,这是我第一次使用 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;

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;

【问题讨论】:

    标签: reactjs redux redux-toolkit


    【解决方案1】:

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

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

    如前所述,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;
    
    

    balance slice - 你不需要一个 slice,你只需要一个选择器

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

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

    【讨论】:

      【解决方案2】:

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

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

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

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

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

      【讨论】:

      • 你能给我一个'extraReducer'的例子吗?以及建议使用哪种方法?
      • 您在文档中有很好的示例:redux-toolkit.js.org/api/createSlice,如果您想要一个具体的示例,请创建一个可生产的示例 (codesandbox)
      • Always go for 是最易读的解决方案,这取决于具体情况 - 因为似乎初学者的问题只是将相关状态传递给有效载荷 (1)。
      • , CALC_TOTAL: (state, action) => { // 如何计算? },我把这个留空?
      • 即使传递了有效载荷,它也只在第二次更新(延迟)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-15
      • 2018-11-20
      • 2021-02-11
      • 2016-04-11
      • 1970-01-01
      • 2019-12-10
      相关资源
      最近更新 更多