# 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:

```javascript
[ Contact, Contact, Contact, ... ]
```

Now it is:

```javascript
{ 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:

```javascript
...
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:

```javascript
state = {
  contacts_list:[],
  error_message:""
}
...
 async componentDidMount(){
    try{
      const response = await fetch('//localhost:8080/contacts/list')
      const answer = await response.json()
      if(answer.success){
        const contacts_list = answer.result
        this.setState({contacts_list})
      }else{
        const error_message = answer.message 
        this.setState({error_message})
      }
    }catch(err){
      this.setState({error_message:err.message})
    }
  }
```

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

```javascript
  render() {
    const { contacts_list, error_message } = this.state

    return (
      ...
        { error_message ? <p> ERROR! {error_message}</p> : false }
      ...
    );
  }
```

(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:

```javascript
...
getContactsList = () => // everything that was in componentDidMount before
...
```

Then:

```javascript
...
componentDidMount(){
  this.getContactsList()
}
...
```

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:

```javascript
SOME_METHOD = async () => {
  try{
    // request something from the rest interface:
    const response = await fetch('http://localhost:8080/contacts/SOME_COMMAND')
    // transform the http response to json (try to parse it as json):
    const answer = await response.json()
    if(answer.success){
      if (answer.success){
        // if successful, do something to the state
        // maybe manipulate the cached contacts in memory to replicate
        // the database changes, or display a message, etc
        this.setState({ SOME_KEY:answer.result })
      }else{
        // set an error in the state
        this.setState({error_message:answer.message})
      }
    }
  }
  catch(err){
    this.setState({error_message:err.message})
  }
}
```

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.

```javascript
...
  getContact = async id => {
    // check if we already have the contact
    const previous_contact = this.state.contacts_list.find(
      contact => contact.id === id
    );
    if (previous_contact) {
      return; // do nothing, no need to reload a contact we already have
    }
    try {
      const response = await fetch(`http://localhost:8080/contacts/get/${id}`);
      const answer = await response.json();
      if (answer.success) {
        // add the user to the current list of contacts
        const contact = answer.result;
        const contacts_list = [...this.state.contacts_list, contact];
        this.setState({ contacts_list });
      } else {
        this.setState({ error_message: answer.message });
      }
    } catch (err) {
      this.setState({ error_message: err.message });
    }
  };

  deleteContact = async id => {
    try {
      const response = await fetch(
        `http://localhost:8080/contacts/delete/${id}`
      );
      const answer = await response.json();
      if (answer.success) {
        // remove the user from the current list of users
        const contacts_list = this.state.contacts_list.filter(
          contact => contact.id !== id
        );
        this.setState({ contacts_list });
      } else {
        this.setState({ error_message: answer.message });
      }
    } catch (err) {
      this.setState({ error_message: err.message });
    }
  };

  updateContact = async (id, props) => {
    try {
      if (!props || !(props.name || props.email)) {
        throw new Error(
          `you need at least name or email properties to update a contact`
        );
      }
      let url="";
      const{name,email}= props;
      if(name && email)
      {
        url=
          `http://localhost:8080/contacts/update/${id}?name=${name}&email=${email}`;

      }
      if(name)
      {
        url=
          `http://localhost:8080/contacts/update/${id}?name=${name}`;

      }
      if(email)
      {
        url=
          `http://localhost:8080/contacts/update/${id}?email=${email}`;
      }

      const response = await fetch(
        url
      );
      const answer = await response.json();
      if (answer.success) {
        // we update the user, to reproduce the database changes:
        const contacts_list = this.state.contacts_list.map(contact => {
          // if this is the contact we need to change, update it. This will apply to exactly
          // one contact
          if (contact.id === id) {
            const new_contact = {
              id: contact.id,
              name: props.name || contact.name,
              email: props.email || contact.email
            };
            return new_contact;
          }
          // otherwise, don't change the contact at all
          else {
            return contact;
          }
        });
        this.setState({ contacts_list });
      } else {
        this.setState({ error_message: answer.message });
      }
    } catch (err) {
      this.setState({ error_message: err.message });
    }
  };
  createContact = async props => {
    try {
      if (!props || !(props.name && props.email)) {
        throw new Error(
          `you need both name and email properties to create a contact`
        );
      }
      const { name, email } = props;
      const response = await fetch(
        `http://localhost:8080/contacts/new/?name=${name}&email=${email}`
      );
      const answer = await response.json();
      if (answer.success) {
        // we reproduce the user that was created in the database, locally
        const id = answer.result;
        const contact = { name, email, id };
        const contacts_list = [...this.state.contacts_list, contact];
        this.setState({ contacts_list });
      } else {
        this.setState({ error_message: answer.message });
      }
    } catch (err) {
      this.setState({ error_message: err.message });
    }
  };

  getContactsList = async order => {
    try {
      const response = await fetch(
        `http://localhost:8080/contacts/list?order=${order}`
      );
      const answer = await response.json();
      if (answer.success) {
        const contacts_list = answer.result;
        this.setState({ contacts_list });
      } else {
        this.setState({ error_message: answer.message });
      }
    } catch (err) {
      this.setState({ error_message: err.message });
    }
  };
  componentDidMount() {
    this.getContactsList();
  }
...
```

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:

```javascript
request = async url => {
  try{
    const result = fetch(`//localhost:8080/contacts/${url}`)
    const answer = result.json()
    if(answer.success){
      return answer.result
    }else{
      this.setState({ error_message: answer.message });
    }
  }catch (error){
    this.setState({ error_message: error.message });
  }
}
deleteContact = async id => {
  const result = await this.request(`delete/${id}`)
  const contacts_list = this.state.contacts_list.filter(
    contact => contact.id === id
  );
  // remove the user from the current list of users
  this.setState({ contacts_list });
};
```

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:

```javascript
  <button onClick={() => this.getContactsList()}>
    Reload
  </button>
  <button onClick={() => this.getContact(2)}>
    Get
  </button>
  <button onClick={() => this.updateContact(2, { name: "a" })}>
    Update
  </button>
  <button onClick={() => this.deleteContact(6)}>
    Delete
  </button>
  <button onClick={() =>this.createContact({ name: "test", email: "testing" })}>
    Create
  </button>
```

**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`:

```javascript
<input type="text" placeholder='name' onChange={(evt)=> this.setState({name:evt.target.value})} value={this.state.name}>
```

And do the same for `email`.

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

```javascript
onNameChange = (evt) => {
  const nameInput = evt.target
  const name = nameInput.value
  this.setState({name})
}
onEmailChange = (evt) => {
  const emailInput = evt.target
  const email = emailInput.value
  this.setState({email})
}
...
<input type="text" placeholder='name' onChange={this.onNameChange} value={this.state.name}>
<input type="text" placeholder='name' onChange={this.onEmailChange} value={this.state.email}>
```

... 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`

```javascript
...
state = {
  ...
  name:"",
  email:"",
}
...
```

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

```javascript
...
  onSubmit = (evt) => {
    // stop the form from submitting:
    evt.preventDefault()
    // extract name and email from state
    const { name, email } = this.state
    // create the contact from mail and email
    this.createContact({name, email})
    // empty name and email so the text input fields are reset
    this.setState({name:"", email:""})
  }
...
```

The whole set of changes looks like so:

```javascript
...
  onSubmit = () => {
    // extract name and email from state
    const { name, email } = this.state
    // create the contact from mail and email
    this.createContact({name, email})
    // empty name and email so the text input fields are reset
    this.setState({name:"", email:""})
  }
  render() {
    const { contacts_list, error_message } = this.state;

    return (
      ...
        <form className="third" onSubmit={this.onSubmit}>
          <input
            type="text"
            placeholder="name"
            onChange={evt => this.setState({ name: evt.target.value })}
            value={this.state.name}
          />
          <input
            type="text"
            placeholder="email"
            onChange={evt => this.setState({ email: evt.target.value })}
            value={this.state.email}
          />
          <div>
            <input type="submit" value="ok" />
            <input type="reset" value="cancel" className="button" />
          </div>
        </form>
      ...
    );
  }
...
```

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:

```javascript
...
  {contacts_list.map(contact => (
    <div key={contact.id}>
      <span>
        {contact.id} - {contact.name}
      </span>
      <button onClick={() => this.deleteContact(contact.id)} className="warning">x</button>
    </div>
  ))}
...
```

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](/docs/02_tutorials/01_react_beginner/c.r.u.d/03.2-react-contact-component.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://codi.gitbook.io/docs/02_tutorials/01_react_beginner/c.r.u.d/03.1-react.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
