React for Beginners #8: Adding and Displaying State with a Click

Lukie Kang
6 min readOct 28, 2018

This is part 8 of my React Learning series. Using knowledge gleaned from Wes Bos’ React for Beginners. Last time we:

  • Built a component to display data
  • In the containing component, mapped through the array (Object.Keys if its an object) to make multiple components
  • Gave each component a unique key.
  • Passed in State data via props
  • Populate the component’s render method with whatever data you want to give it.

Let’s look again at how we add things to state, this time via a onClick event.

The setup

This time we are using the example of a shopping basket, with a number of grocery items that has be added to it. We have three specific components involved:

  1. Grocery — A div for each item, Where we also have an ‘Add’ button for each item
  2. Order — Where we can see what we have ordered with total for that order.
  3. App — The parent component with a state that contains two objects: — grocery which displays a specific item on sale - order which will contain the order for the user. Currently blank.

So the general idea is to:

  1. Create a function to add the associated grocery to the order, multiple times if needed.
  2. Display the order on the Order component, totting up the prices as required.
  3. On the Groceries component, configure a button with an event method to handle the click to add to the order.

Making an Add to Order function

As we are updating the state on the app component, we want to have the method here as well. The method must do three things:

  1. Take a copy of the relevant part of state
  2. In this copy, add a grocery to the order or increment the current grocery by 1;
  3. Update the state

Taking a copy of state

This just relies on using the spread operator:

const order = {...this.state.order}

Add to Order or Increment By 1

This uses a little trick where the OR statement runs the first condition if the item exists or else makes it exist by adding a 1.

order[key] = order[key] +1 || 1;

Use setState to Update the State

this.setState({ order })

Note that order is used to update order in the State, that’s order:order which shortens in ES6 to order

Here is the method in it’s entirety:

Passing the Method and Key to the Button’s Component

The button we want to add lives in the grocery component which shows details about the particular grocery (name, price.. etc)

As app is the parent of the grocery component we need to first pass the method into props: addToOrder={this.addToOrder}

Now we have a slight quandry, the method needs the object key passed into it. As the component is created without visabiity of its own key, how do we get that?

The answer is that we need to pass it through as a prop as well...

index={key}

Setting the Event on the Button

First lets create the event on the button:

<button onClick={this.handleClick}>

Second, lets create that handleClick function property on the component:

handleClick = () => {this.props.addToOrder(this.props.index)}

Some people might like to put the function on the method inline on the button, but I like separating it out for clarity.

Cool, if everything has gone to plan we should be able to see items being added to the App state when we click that button. Now for the other side of the equation, displaying what we have just placed into state.

Displaying the State object on our Order form

Now that we have the state getting updated when we hit our button, we probably should show the result of that somewhere. Much of this going to involve dealing with edge cases that may or not apply in your scenario. Essentially we need to pass in the relevant prop and display the data as we loop through each key.

Our order form in this example, needs to show the following things:

  1. The item(s) we have ordered
  2. How many of each item we have ordered
  3. The price of that item multiplied by the amount.
  4. The whole total.
  5. Check if the grocery item becomes sold out and react accordingly.

Getting the Props

So before we do anything else, in App.js we need a prop to pull in the groceries and order objects:

  • The groceries object contains the name, price and status of each grocery
  • The order object contains how many of each item has been ordered.

We need both to figure out things so pull them into the Order component like so:

<Order groceries={this.state.groceries} order={this.state.order}/>

You might be tempted to add all of the state as that’s the currently the only objects in it, but in the spirit of using only what we need, we cannot be sure that will always be the case so its good practise to be explicit in what you are taking in as props.

Working with the Prop Data

In the Order.js file we can build some variables we could use:

An array of Object Keys

const orderIds = Object.keys(this.props.order) -

This gives us an array of each key in the order object. If we display that using {orderIds} we should have each order item appear.

A total of all items We have to check a few things as we figure out the total via the Reduce array helper method:

Remember to actually display, and style the total somewhere: {total}

Loop over the OrderIds

  1. In the JSX we are returning, make a <ul> to contain the OrderIds we will display.

2. In the UL, map over the orderIds to return an list item for each item ordered: OrderIds.map(key => <li>{key}</li>)

The JSX will look something like this:

Render Functions

By now your render function is starting to get a little long, which is a sign too much is going on in your component. We could make a component for the code but if its not quite big enough we can shunt some of the code to a function inside the component, removing it from render

For example we can take the logic for each list item above and put it into a function on the component like so:

Now the unordered list can look like this:

<ul>{orderIds.map(this.renderOrder)}</ul>

It’s a fairly basic example but its something to bear in mind as a middle ground between putting everything in `render` and making another component.

Presumably you will want to show more than just the key for each order, but that’s a detail you can figure out for your own needs! Some extra details may include:

  • The grocery name
  • The count of orders for that grocery
  • The price of (grocery.price * count)
  • Check if the grocery is still available and change the list item should it become unavailable during the order.

Once you start adding that complexity, using a Render method starts making more sense.

Add keys to each List item

As we have created multiple similar list items, React will get a little upset and warn us about the lack of unique keys for the list items. React wants there to be unique keys for each component to allow it to rapidly reference and change.

This is fairly straightforward to sort since our Grocery Object keys are also unique:

<li key={key}> {key} </li>

Conclusion

As long as we set up the props and manage the amount of code in our render function there is little React-specific knowledge required for displaying State data. Having a good grasp of JS though will make life easier when it comes to getting the right bit of data from our props and displaying it efficiently. the rest is up to what exactly you want to display with your State data.

--

--