React Part I

We now have a controller, an http interface for it.

We need to use this from the front-end, through React.

We were already using one route, contacts/list, which gave us the list of contacts.

We need to change it slightly, because previously, the data received was a list of contacts in the form:

[ Contact, Contact, Contact, ... ]

Now it is:

{ success: true,
  result: [ Contact, Contact, Contact, ... ]
}

(or {success:false, message:"blah blah"})

So, let's change our class a bit:

Where it used to say:

...
state = {
  contacts_list:[]
}
...
 async componentDidMount(){
    const getList = async()=>
    {
        try{
          const response = await fetch('//localhost:8080/contacts/list')
          const data = await response.json()
          this.setState({contacts_list:data})
        }catch(err){
          console.log(error)
        }
    }
    getList();
  }
...

make it do:

Now, if the json sends back an error, it will be stored int he state.

We also changed the catch to store the error in state too.

The error is stored in the state, but we can't see it at the moment.

Let's do something in the render too, to show the error. We will add a conditional, which will show the error if it is there

(if you're using a component framework such as react-native-web, replace <p> by <Text> or whatever relevant)

Try it! Run npm start from the root, to run both the front end and the back end. It should work just like it used to.

You can try to change the url in the fetch function, and see the error messages pop up (you may have to scroll up or down to read it, depending where you put it).

Implementing the CRUD methods in the React Component

Now, let's implement the other methods. We're going to just follow, again, the same protocol we had in the controller, and the rest interface. This is not necessary, but makes it easier to understand.

We're going to need:

  1. getContact

  2. deleteContact

  3. updateContact

  4. createContact

  5. getContactsList

The item #5, getContactsList, already exists; it is just running automatically inside onComponentDidMount. We're going to take it out of there. Take everything inside of componentDidMount and put it in a method getContactsList, written like so:

Then:

This way, our code works exactly the same as before, but we've made getContactsList reusable. We can now call it from other places than componentDidMount.

Swell. Let's implement the skeleton of the other methods. They all follow the same pattern:

Below is the full implementation of all the methods.

This is going to be long, but if you look at the methods closely, you will notice they actually do not differ greatly from each other.

This is a lot to take in, so take a moment to observe each function individually. I don't advise copy pasting, but rather to copy each function manually, so you can understand what it does.

note: of course, we could abstract away the repeating parts, such as fetch...then...catch.... For example, we could have a function that goes:

But for the moment, we keep things stupid and simple.

We might, later, discover we need to handle specific methods in specific ways (for example, checking that the user is allowed to pursue the action, or needing to display a confirmation dialog). At that point, having a lot of abstraction would make things harder. This is an example of early optimization, and is something to generally avoid.

Thus, we'll keep things stupid and simple. We can add all the indirection we want later ("indirection" is the process of adding pathways to the code, which abstracts away things, but makes each function less readable by itself, because you need to jump around to understand it).

Very well, we will now proceed to try those methods from the user facing React.

We will create four buttons, which will each call a method, to test it. Somewhere in render, write:

note: With react-native-web you should use onPress instead of onClick, and use title="" instead of writing the text in the button's children

You can try the buttons. However, of course, some of them you can only try once. For example, when you press delete, you will need to provide another id next time, since the id you deleted was, well, deleted. But that's ok. You can manually change the parameters, test again. Once you are satisfied, remove the buttons. We will implement the actual behavior properly in the next steps.

First, let's try to create new contacts. We're going to need two text inputs. Import TextInput if you're using react-native-web, or simply use an <input type="text"> if you're using regular html. Then, in render:

And do the same for email.

Notice that we haven't created handlers for the inputs. We could've created two handlers like so:

... But our component is cluttered enough with all those CRUD methods, so we're creating those handlers directly in-place.

note: this means the handlers are re-created every time a render occurs, which will come with a performance penalty; but we can always create those handlers later if we want to.

don't forget to add the keys name and email to state

Then, add a form, which, when submit, runs the function onSubmit (which doesn't exist yet, we will create it).

The whole set of changes looks like so:

Whoa! We can add things to our database now. Did you try the form?

Let's think about where the other things would fit:

  1. we want a delete button next to each item

  2. we want an input field next to each item so we can edit it

Let's start with the delete button. Change the contact list loop to:

Try to delete a few contacts. Neat!

Now, the edit. This is going to be significantly harder.

We want to:

  1. have a field for the name

  2. have a field for the mail

  3. we want both fields to be linked to the actual value (as in the contact's name should display in the field)

  4. we want to be able to reset the field and restore it to the previous value (if the user didn't press "ok")

  5. we probably want, later, to display error messages and feedback messages, and do all sort of things

  6. most likely, we will have more fields than name and email, so this is going to grow, a lot.

  7. also, we don't want this edit form to show all the time; it should show only if we are actually editing the component

That's a lot of things to do. We'd better create a whole new component for it.

Hang in there, take a breather, make some coffee, then let's move to Part 2 - Contact Component

Last updated

Was this helpful?