[Project Expense Cards] - Adding expense rows dynamically via a button

It took awhile to figure out, but I finally figured it out without much help from Google sensei.  Remember, this app is a prototype I'm building using React as a way to learn and get a taste of React.  I am a complete noob with React so I'm using as much as I can from what I learn throughout.

The button

First part was getting a button on the screen.  Now, if this was just plain ol' HTML with CSS and JavaScript, then it would take seconds, but this is React so I had to think differently.  I created a new component specifically just for the component.  Simple components that know only how to do one thing is a good thing!  I created 2 parts for this button: a presentational component and a container component.  This is the container component design pattern.  This pattern is also mentioned in Codecademy's React tutorial course.  Here's a link that explains the design pattern more: https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#….

Making the button work

The next part was to get the button to add table rows of empty fields into the table when the button is clicked. At first I thought, "I could probably use jQuery or plain ol' vanilla JavaScript to manipulate the DOM alongside React, right?" but then I thought maybe that wasn't going to be such a good idea from past experiences with AngularJS. Instead, I opted to do it purely the React way. There are, of course, ways to also use jQuery with React but doing it the React way will teach me a better, solid design pattern.

I put the function to handle adding a new expense row in my container component, ExpenseCardContainer, instead of AddExpenseButtonContainer.  Why? Because the array of expenses is initialized in ExpenseCardContainer component.  

When I click the button, I want a new expense added to that array of expenses.  To achieve this, the function is passed to my AddExpenseButtonContainer, which is a child component of ExpenseCard.  Then the component, AddExpenseButtonContainer, handles the function by calling that function from the props object and passing it an argument.  This then changes the state of ExpenseCardContainer because the new expense is added to the expenses array.  Okay, that may have sounded confusing so hopefully the code below provides some clarity.

  1. class ExpenseCardContainer extends React.Component {
  2. constructor(props) {
  3. super(props);
  4.  
  5. this.state = {
  6. currentExpenseRowId: 0,
  7. expenses: []
  8. };
  9.  
  10. // Bind custom functions to be able to use them.
  11. this.addNewExpense = this.addNewExpense.bind(this);
  12. }
  13.  
  14. // Function for adding a new expense.
  15. addNewExpense(newExpense) {
  16. var currentExpenseRowId = this.state.currentExpenseRowId + 1;
  17. newExpense.id = currentExpenseRowId;
  18.  
  19. var updatedExpenses = Array.isArray(this.state.expenses) ? this.state.expenses.slice() : [];
  20.  
  21. updatedExpenses.push(newExpense);
  22.  
  23. this.setState({
  24. expenses: updatedExpenses,
  25. currentExpenseRowId: currentExpenseRowId
  26. });
  27. }
  28.  
  29. render() {
  30. return (
  31. <ExpenseCard>
  32. <AddExpenseButtonContainer
  33. onClick={this.addNewExpense} />
  34. <ExpenseListContainer
  35. expenses={this.state.expenses} />
  36. <ExpenseTotalContainer
  37. expenses={this.state.expenses} />
  38. </ExpenseCard>
  39. );
  40. }
  41. }

There were some other tweaking needed to get it done but it was mostly in regards to moving things around and making sure they're in the right spot. So far, so good! Checkout a screenshot below for progress:

2016-12-06 17_46_42-Finance.png