My GIthub link for the Expense Tracker project
Expense Tracker
Before we get started, let’s spend some time using the app in its current implementation to ensure we understand how it’s supposed to work.
Note: I suggest to rebuild our App’s file structure for a more comprehensive understanding (as shown in the first commit).
Create a Budgets Slice
At the top of budgetsSlice.js:
1a. Import createSlice from @reduxjs/toolkit.
Redux Toolkit Documentation
import createSlice from '@reduxjs/toolkit';
Define a slice by calling createSlice() with a configuration object containing the required name, initialState, and reducers properties. Redux Toolkit Documentation
2a. Define a variable, budgetsSlice, and initialize it with a call to createSlice(), passing in an empty configuration object. Do this right after the line defining initialState.
const budgetsSlice = createSlice({
});
2b. Slices are conventionally named for the resource whose state they manage. This slice manages budgets and should be named accordingly. To give the slice a name, add a name property to the configuration object and set it equal to ‘budgets’.
const budgetsSlice = createSlice({
name: 'budgets',
});
2c. Add an initialState property to the configuration object, and set it equal to the variable initialState that we’ve defined for you.
const budgetsSlice = createSlice({
name: 'budgets',
initialState: initialState,
});
2d. Lastly, you’ll need to include a reducers property in the configurations object. For now, set it equal to an empty object.
const budgetsSlice = createSlice({
name: 'budgets',
initialState: initialState,
reducers: {
},
});
3a. Add an editBudget property to the reducers object passed to createSlice().
const budgetsSlice = createSlice({
name: 'budgets',
initialState: initialState,
reducers: {
},
});
3b. Set editBudget equal to a case reducer that receives two arguments—state and action . action.payload will have a category and amount property.
const budgetsSlice = createSlice({
name: 'budgets',
initialState: initialState,
reducers: {
// Set editBudget equal to a case reducer that receives two arguments—state and action
editBudget: (state, action) => {
// action.payload will have a category and amount property.
const {category, amount} = action.payload;
}
},
});
3c. editBudget should update the state by finding the budget object whose .category value matches action.payload.category and changing with the .amount value to action.payload.amount.
const budgetsSlice = createSlice({
name: 'budgets',
initialState: initialState,
reducers: {
// Set editBudget equal to a case reducer that receives two arguments—state and action
editBudget: (state, action) => {
// action.payload will have a category and amount property.
// const {category, amount} = action.payload;
const category = action.payload.category;
const amount = action.payload.amount;
// Update the state by finding the budget object
// Note: the variables category and action, implemented below, are each assigned action.payload (referenced in the above const).
// Ex. category = action.payload.category ;
// Ex. amount = action.payload.category;
// The budget object whose .category value matches action.payload.category and changing with the .amount value to action.payload.amount.
state.find(budget => budget.category === category).amount = amount
}
},
});
Delete your old code and clean up your exports.
4a. Delete the stand-alone editBudget. At the bottom of the file budgetsSlice.js, export the editBudget action creator generated by createSlice() and stored in budgetsSlice.
// export const { myActionCreator } = mySlice.actions;
export const { editBudget } = budgetsSlice.actions;
4b. Delete the stand-alone budgetsReducer, and update the export default statement to export the reducer generated by createSlice() and stored in budgetsSlice.
// export default mySlice.reducer;
export default budgetsSlice.reducer;
Checkpoint 1: We are now able to edit budgets and see out changes reflected in the app.
In transactionsSlice.js:
5a. Import createSlice from @reduxjs/toolkit.
import createSlice from '@reduxjs/toolkit';
Define a slice by calling createSlice() with a configuration object containing the required name, initialState, and reducers properties.
6a. Define a variable, transactionsSlice, and initialize it with a call to createSlice(), passing in an empty configuration object.
const transactionsSlice = createSlice({});
6b. Add a name property to the configuration object and set it equal to ‘transactions’.
const transactionsSlice = createSlice({
name: 'transactions',
});
6c. Add an initialState property to the configuration object, and set it equal to the variable initialState that we’ve defined for you.
const transactionsSlice = createSlice({
name: 'transactions',
initialState: initialState,
});
6d. Lastly, you’ll need to include a reducers property in the configurations object. For now, set it equal to an empty object.
const transactionsSlice = createSlice({
name: 'transactions',
initialState: initialState,
reducers: {},
});
Replace these stand-alone action creators and the reducer with case reducers defined in the object passed to createSlice().
7a. Add an addTransaction property to the reducers object passed to createSlice().
const transactionsSlice = createSlice({
name: 'transactions',
initialState: initialState,
reducers: {
addTransaction: () => {},
},
});
7b. Set addTransaction equal to a case reducer that receives two arguments—state and action. It should add the new transaction object (action.payload) to the correct category’s transaction list in the transactions state object.
const transactionsSlice = createSlice({
name: 'transactions',
initialState: initialState,
reducers: {
addTransaction: (state, action) => {
// add the new transaction object (action.payload) to the correct category’s transaction list in the transactions state object.
const category = action.payload.category;
state[category].push(action.payload);
},
},
});
7c. Add a deleteTransaction property to the reducers object passed to createSlice().
const transactionsSlice = createSlice({
name: 'transactions',
initialState: initialState,
reducers: {
addTransaction: (state, action) => {
// add the new transaction object (action.payload) to the correct category’s transaction list in the transactions state object.
const category = action.payload.category;
state[category].push(action.payload);
},
// Add a deleteTransaction property
deleteTransaction: () => {
}
},
});
7d. Set deleteTransaction equal to a case reducer that receives two arguments—state and action. It should delete the old transaction (action.payload) from the correct category’s transaction list in the transactions state object.
const transactionsSlice = createSlice({
name: 'transactions',
initialState: initialState,
reducers: {
addTransaction: (state, action) => {
// add the new transaction object (action.payload) to the correct category’s transaction list in the transactions state object.
const category = action.payload.category;
state[category].push(action.payload);
},
// Add a deleteTransaction property
deleteTransaction: (state, action) => {
// In the deletedIndex in transactionsReducer, action.payload.category and action.payload.id are both used.
const id = action.payload.id;
const category = action.payload.category;
// It should delete the old transaction (action.payload) from the correct category’s transaction list in the transactions state object.
// 1. Find the category in `state` that matches the `category` property on `action.payload`
// 2. Filter out the old transaction (the transaction with an `id` matching the `id` property on `action.payload`) from that category's transaction array.
state[category] = state[category].filter(transaction => transaction.id !== id)
}
},
});
Delete your old code and clean up your exports.
8a. Delete the stand-alone addTransaction and deleteTransaction,
8b. Export the addTransaction and deleteTransaction action creators generated by createSlice()and stored in transactionsSlice.
export { addTransaction, deleteTransaction } from transactionsSlice.action;
8c. Delete the stand-alone transactionsReducer,
8d. Update the export default statement to export the reducer generated by createSlice() and stored in transactionsSlice.
export default transactionsSlice.reducer;