React for Beginners #11 — Editing and Deleting Items from State

Lukie Kang
6 min readOct 28, 2018
Not the most exciting picture, but I dare you to find better for ‘edit’ and ‘delete’…

This is part 11 of my React Learning series. Using knowledge gleaned from Wes Bos’ React for Beginners.

So far we have our application being able to Create and Read, with a sync to a database and localstorage for relevant parts. Let’s look at Updating and Deleting to get the whole CRUD thing complete.

Coming from a REST API point of view, When we create an Edit form, we have four main steps:

  1. Get the data that currently exists for an item.
  2. Show the data for the user to look at
  3. Allow the user to edit the data they are being shown.
  4. Put the changed data back to replace what was originally there.

React is a similar story, we can use a component, props and state to get up a two way data flow to keep things up to date. The joy of react is doing this ‘live’, seeing those values change the moment the user changes them as opposed to needing a submit action.

Setting up our Edit Component

First of all, lets see about making a component to show the item details we want to edit. Of course, since we are being awesome React devs, we will build a single Edit component inside of our Inventory component and loop through our Groceries object, each time populating the Edit component with existing data for each Grocery.

  1. Make a new class based component called EditGroceryForm
  2. Import React
  3. Export the EditGroceryForm class function you made
  4. For now, lets set the render method to just return a placeholder like <p> hey </p>

We will flesh it out some more once we have it integrated into our Inventory component.

Adding the State data and Edit Form to our Inventory

There are core things we need in our Inventory component, the state data for our groceries and an edit form for each of them

  1. The parent inventory component currently does not have access to the groceries object in state so we need to pass in the prop: groceries={this.state.groceries}
  2. Remember to import the EditGroceryForm into our Inventory Component.
  3. Map through the groceries object and return the EditGroceriesForm component:

{Object.keys(this.props.groceries).map( key => <EditGroceryForm grocery={this.props.groceries[key]} key={key}/>)}

Some things to note in the above:

  • We need to need a prop to pass through each grocery.
  • We need a second prop to pass through the key called index
  • We add a key to make sure each component is unique

If all goes to plan, we should have multiple components rendered. However we probably want to show something more helpful than a paragraph tag so lets flesh it out some more…

Setting up the Inputs

So for an edit form to work we do need some inputs. For each grocery we have the following fields:

  • name (input)
  • price (input)
  • status (select)
  • desc (textarea)
  • image (input)

If you have already created an add form, it might be useful to copy from there and tweak it.

The really important bits

  • Each of the form elements should have a name property: e.g name='price'
  • The value property should be pulled in from props: e.g value={this.props.grocery.price}

However we will get the following warning at this point: Failed Prop type. You provided a ‘value’ prop to a form field without an onChange handler. Basically will stop us from editting the field as soon as we try to update the field, it will replace it with the entry in State. So we need to change state to change the input which we can do with an onChange event.

The onChange event

First add the event to the form fields: onChange={this.handleChange}

Then we want to make a method that will:

  1. Get the value that was entered (but not displayed)
  2. Create a copy of the current grocery from state
  3. Figure out what value has changed
  4. Update the copy with the new value.

Lets explain that last line a little:

  • The event.currentTarget.value gives us the value of whatever input triggered the event...
  • The event.currentTarget.name will tell us what the name propery of the target was. However wrapping it in the square brackets allows us to use it as a dynamic computed property name so it will change the property based on the name value of the input. This is a little wierd but allows all the inputs to need only this one method.

That was a little frightening, but we have one last thing to do, update the state with the updated Object we have just made.

Updating the state

Back in our App component we can make a property for the function that updates the grocery. This requires two arguments:

  1. key - the key for the particular grocery we want to update
  2. updatedGrocery - the new grocery we want to replace it with... which should sound familiar...

This will perform three jobs:

  1. Take a copy of the state: const groceries = [...this.state.groceries]
  2. Update the copy : groceries[key] = updatedGrocery
  3. Set the updated copy to state: this.setState({ groceries })

This is what you should end up with:

Now we have the property, we can pass it to the Inventory using Props: updateGrocery = this.updateGrocery In our Inventory component we again need to pass it into our EditGroceryForm component. However we should now have the updateGrocery method available in our EditGroceryForm component.

However, for the property to work it needs to know the key, the EditGroceryForm component doesn't know what key it is referring to unless we pass that through as a prop. Since we already have a key, lets call it index: index = {key}

So now we have access to it, lets use the method to complete our event:

We now have the input changing state which changes itself based on the user’s input!

Edit — Overview

Using inputs to change values is actually fairly straightforward conceptually:

  1. Set up an input
  2. Make an event to capture the user’s input
  3. The user’s input updates the state
  4. The state updates the input.

However, to do it requires a fair amount of props and props flying around so its something that can easily go wrong if you don’t take it step by step.

Appetite for Destruction

So we looked at sorting out an edit form. This means that so far, we have been able to:

  • Create an item
  • Read an item
  • Update an Item.

So you can assume the last thing will be…

Delete an Item

This one isn’t too tough as its similar to the process we had before, but even easier. The basic steps are:

  1. Make a method that deletes a certain property from the groceries object.
  2. Create a button to trigger the method
  3. Pass the method down to where the button is

Our delete method

The delete method is created on our app.js as that is where our state is. It needs to do the following.

  1. Take in a key so we can find the right item to delete.
  2. Make a copy of the state.
  3. Set the value of the item to null
  4. Save the modified variable to state.

You might wonder why we dont just delete the item? Well as we are using Firebase, it will have trouble syncing something that doesnt exist so its best to keep the key but with no value.

So to delete a grocery the method should look like this:

We can test it in the console by using $r to select the app component and running: $r.deleteGrocery('grocery1') (assuming 'grocery1' is the key)

Hooking that method to a button

We have the method but we need a way for the user to run it. A button with an event should do the trick!

We can use the edit form before to add a button as follows:

<button onClick={ () => this.props.deleteGrocery(this.props.index)}> Delete </button>

Here we use an inline function to just do it on one line.

Now the last thing to do is pass the deleteGrocery method down to the EditGroceryForm component where the button lives.

I think have talked about props enough but here is the gist of what we want:

  • deleteGrocery={this.deleteGrocery} ... from App JS
  • deleteGrocery={this.props.deleteGrocery} ... from elsewhere.

If you have your props, button and method correct. It should all work!

Deleting Wrap Up

You should have your deleting sorted. Generally it is easier than editing as you don’t need to worry about swapping it with another value. Just remember to be aware of circumstances where you can actually delete and where its best to leave a ‘null stub’

--

--