Building Your First React App with Hooks (and Git) (Part II)
Tags: react, hooks, frontend, beginners
Published: 2021-09-16 18:12:30

This tutorial is a continuation of the [React tutorial Part I](https://dev.to/brunodasilva/building-your-first-react-app-with-hooks-part-i-1bob). If you haven't finished the previous one, I suggest you go back and complete that one first before jumping into this one.

The goal is to continue building our first React app, including now state handling, along with using Git and GitHub.

_This article was initially created as a lab assignment in an intro to software engineering course I've taught at Cal Poly. A series of other articles has been published. I hope you follow along!_

$$ 0 - Installing git (skip if you already have git installed)

Follow this link to install git according to your OS: [https://git-scm.com/book/en/v2/Getting-Started-Installing-Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)


Run `git --version` to make sure it is installed.

##1 - Creating a git repository

Here we'll initialize your app folder to be tracked by git.  In the terminal, 'cd' to your React app folder and run `git init` in it. From now on, your project folder is locally tracked by Git.

Go to [github.com](github.com) and create a repository at GitHub. If it's your first time on GitHub, you'll need an account. Note 1: At this time, DO NOT check 'initialize this repository with a README' and DO NOT check 'Add .gitignore'. You can work on the readme and gitignore files for your repo later.  

##2 - Committing changes and pushing

Next, we'll commit our changes. If you're new to git, remember that there are files we never commit. For instance, the `/node_modules` folder of your app contains your local libs. Every developer collaborating in your project would have their own `/node_modules` folder managed when running their npm commands. So, we'll make sure the '/node_modules' folder is in our `.gitignore` file.

In the root of your app folder open this file '.gitignore' and check if there's this line:
`/node_modules`

If you're following this tutorial having done [Part I](https://dev.to/brunodasilva/building-your-first-react-app-with-hooks-part-i-1bob) already, you'll see the .gitignore file with this line already (it was created when you ran the `npx create-react-app` command from Part I). Otherwise, create the .gitignore file by yourself in the root folder and add that line.

This will make git ignore whatever you place in that file and never track what's in there.

To commit changes, we have to stage our files. So, first, stage everything in your app folder except the /node_modules (we already added it to our gitignore file). For instance, here's how you stage your /src folder:

`git add src`

Run `git status` to check what's staged and what's unstaged.  Anytime you're lost, the `git status` command will be helpful.


Once everything is staged, you'll commit changes. Remember that, on git, we commit locally and, only after that we can push one or more commits to a remote repository (e.g., GitHub). It's a good practice to add a commit message to communicate what represents your code changes. Even if it's obvious, place a clear and concise message since, in general, these messages can be used to understand the history of code modifications and help maintenance activities.

`git commit -m 'First commit of my react app'`

Now we're almost ready to push changes to your remote GitHub repo. We need first to tell your local git repository that you have a remote host. Here's the command to do it (you'll also see these instructions on your GitHub repo page once you create the repo):

`git remote add origin https://github.com/your-username/your-repo-name.git`

This is the only time you have to run the git remote add command.

Now, locally in our git, we'll rename our 'master' (default) branch to 'main' with the following command (GitHub already recognizes 'main' as the default branch). As a side note: technically, this is not a required step, but ethically the best choice [[1]](https://www.wired.com/story/tech-confronts-use-labels-master-slave/) [[2]](https://www.cnet.com/news/microsofts-github-is-removing-coding-terms-like-master-and-slave/) [[3]](https://www.pcmag.com/news/apple-to-remove-masterslave-and-blacklist-terms-from-coding-platforms).

`git branch -M main`

Then, we'll call the actual push to GitHub:

`git push -u origin main`

Finally, you should be able to visit your GitHub repo online. Visit github.com/your-username/you-repo-name, and you will see your commit there. 

To exercise one more useful command, on GitHub, edit the existing README.md file (or create a new one) following their web interface. If you've followed all the steps since Part I you should see a README file already pushed to GH. If for some reason you don't see one, you'll see a button "Create Readme." If there's a readme.md already in your root folder, you can click on that file and then edit it on GH interface to represent a change in the remote repo. Once you hit that button and edit or create a readme file, GitHub will generate a commit triggered by its web interface. 

When you're done with it by either editing an existing readme file or creating a new one, you still won't have this commit/change in your local repo. So, go to the terminal and run `git pull` to bring the commit to your repo (remember that git pull executes a `git fetch` and a `git merge` at once). Now, the readme file is also local since you just synchronized your local repo with the remote repo.

##3 - State (back to React)

So far, we're storing our character data in an array and passing it through as props. This is good to start, but imagine if we want to be able to delete an item from the array. With props, we have a one-way data flow, but with state we can update private data from a component.

You can think of state as any data that should be saved and modified without necessarily being added to a database - for example, adding and removing items from a shopping cart before confirming your purchase.

There are different ways to handle state in React. Since we're using React functional components, we'll use the now-famous [React Hooks](https://reactjs.org/docs/hooks-intro.html). Hooks were added to React in 2018 (which makes it a relatively recent feature as of 2021). It's a promising feature that makes state handling code more readable and easier to maintain. There are tons of materials online to go in-depth about it, and the [official React doc](https://reactjs.org/docs/hooks-overview.html) is a good starting point.

To start handling state with React Hooks, we need to understand what our state is. In our case, it'll be the `characters` array. And we'll use the so-called `useState()` Hook to add some local state to the MyApp component. The useState call returns a pair: the current state value and a function that lets you update the state. You can call this function from an event handler or somewhere else (we'll do it soon).

**Inside src/MyApp.js**

```React
import React, {useState} from 'react';
import Table from './Table';

function MyApp() {
   const [characters, setCharacters] = useState([  
      {
        name: 'Charlie',
        job: 'Janitor',
        // the rest of the data
      },
    ]);
}
```

Our data is officially contained in the state owned by the MyApp component (rather than contained as a constant in a function). Since we want to be able to remove a character from the table, we're going to create a `removeOneCharacter` function on the parent `MyApp` component. Note that it is a nested function. Since that function, removeOneCharacter, needs the 'characters' state, they need to be in the same scope.

To retrieve the state, we'll refer to the corresponding state identifier `characters`. To update the state, we'll use `setCharacters()`. We'll filter the array based on an `index` that we pass through, and return the new array. The [filter function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) is a powerful Javascript built-in function worth checking if you're not familiar with.


You must use `setCharacters()` to modify the state instead of trying to assign a new value directly to characters. When you call setCharacters in the component, React automatically updates the child components inside it too (that is, React re-renders the child components to update them).

**Inside src/MyApp.js**

```React
import React, {useState} from 'react';
import Table from './Table';

function MyApp() {
   const [characters, setCharacters] = useState([  
      {
        name: 'Charlie',
        job: 'Janitor',
        // the rest of the data
      },
    ]);

   function removeOneCharacter (index) {
      const updated = characters.filter((character, i) => {
         return i !== index
      });
      setCharacters(updated);
   }

}
```

`filter` does not mutate the original array but rather creates a new array after applying the filtering. And our filtering criterion is defined by a conditional statement. The conditional is testing an index vs. all the indices in the array, and returning all but the one that is passed through. 

Also, note that we defined the removeOneCharacter function within the MyApp main function. With that, we can be in the right scope to refer to characters and setCharacters, and since this function will only be used within the MyApp component (which is a function by itself). Btw, we'll now see how that new function will be called.

Now, we have to pass that function through to the component and render a button next to each character that can invoke the function. First, we'll pass the `removeOneCharacter` function through as a prop to `Table`.

**Inside src/MyApp.js (only showing the return -- the component render)**
```React
  return (
    <div className="container">
      <Table characterData={characters} removeCharacter={removeOneCharacter} />
    </div>
  );
```

Note the added prop is `removeCharacter` and its value in that scope is `removeOneCharacter`.

Since our `Table` component is passing the props down to `TableBody`, we're going to have to pass the new prop through as well, just like we did with the character data.

**Inside src/Table.js**
```React
function Table(props) {
  return (
    <table>
      <TableHeader />
      <TableBody characterData={props.characterData} removeCharacter={props.removeCharacter} />
    </table>
  );
}
```

Now, here's where that index we defined in the `removeOneCharacter()` function comes in. In the `TableBody` component, we'll pass the key/index through as a parameter, so the filter function knows which item to remove. We'll create a button with an `onClick` property and pass the index through. If you're not very familiar with HTML, [button is an HTML tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) that has an attribute called [onClick](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick) used to assign action when the button is clicked. The only change in the TableBody component is in the return call by adding a new column to the table that'll have a button with an action.

**Inside src/Table.js (only changing inside the return of TableBody component)**
```React
<tr key={index}>
  <td>{row.name}</td>
  <td>{row.job}</td>
  <td>
    <button onClick={() => props.removeCharacter(index)}>Delete</button>
  </td>
</tr>
```

Great! Now we have delete buttons on a new column and we can modify our state by deleting a character. I deleted Mac in the screenshot below.

![Screenshot of the delete buttons on the page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ji2v1etwidv4m9x21bvv.png)

**Now you should understand how state gets initialized and how it can be modified.**

Oh, and if you want to add a column label to that new column we added in the table body (see the 'Remove' label in the picture above), guess where you should change it? Go ahead and do it for aesthetic purposes.

##4 - Committing changes and pushing them to GitHub

It's always a good practice to breakdown your programming sessions into small commits. So, now it's a good time to commit the changes you've made up to this step. Remember to stage your files, otherwise, there's nothing to commit. Git is tracking your changes. Run git status to check what git has to tell you. Then, run `git add <files>` to stage the files (you can stage them at once using regular expressions). 

Once they're staged, run `git commit -m 'your commit msg.'`

Finally, run `git push` to push your commit to GitHub.

##5 - Creating a form to input data

Back to the project, now we have data stored in **component state**, and we can remove any item from our list of characters inside the component state. However, what if we wanted to be able to add new data to the state? In a real-world application, you'd more likely start with empty state and add to it, such as with a to-do list or a shopping cart.

Before anything else, let's remove all the hard-coded data from `characters`, as we'll be updating that through an input form now.

**Inside src/MyApp.js (empty state)
```React
   const [characters, setCharacters] = useState([]);
```

Now, let's go ahead and create a `Form` component in a new file called `Form.js`. We're going to set the initial state of the `Form` to be an object with some empty properties.

**src/Form.js**
```React
import React, {useState} from 'react';

function Form() {   
   const [person, setPerson] = useState(
      {  
         name: '',
         job: '',
      }
   );

}
export default Form;
```

Our goal for this form will be to update the state of `Form` every time a field is changed in the form, and when we submit the form, all that data will pass to the `MyApp` state (feeding the list of characters), which will then update the `Table`. Remember that when a component state changes, it triggers an update on the child components. State handling is where all the magic happens in React!

First, we'll make the function that will run every time a change is made to an [input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). The **event** will be passed through, and we'll set the state of ``Form`` to have the **name** and **job** of the inputs.

**Add the following code to src/Form.js**
```React
function handleChange(event) {
  const { name, value } = event.target;
  if (name === "job")
     setPerson(
        {name: person['name'], job: value}
     );
  else
    setPerson(
        {name: value, job: person['job']}
     );   
}
```

The function above should be defined inside the Form function since it sets the state defined inside the Form component. They need to be in the same scope.

Also, note that there's only one event at a time (either changing the name or the job field), so the function above will be called every time one of the fields (name or job) changes its value (i.e., when the user types in something).

Let's get this working before we move on to submitting the form. In the render (return call), let's get our two properties from state, and assign them as the values that correspond to the proper form keys, so the state (person) will be our source of truth for the form fields. We'll run the `handleChange()` function as the `onChange` of the [input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).

**Inside src/Form.js (the return call of the Form function)**
```React
return (
    <form>
      <label htmlFor="name">Name</label>
      <input
        type="text"
        name="name"
        id="name"
        value={person.name}
        onChange={handleChange} />
      <label htmlFor="job">Job</label>
      <input
        type="text"
        name="job"
        id="job"
        value={person.job}
        onChange={handleChange} />
    </form>
); 
```

In `MyApp.js`, we can render the form below the table. A new import for bringing in the Form component to src/MyApp.js

```React
import Form from './Form';
```

**src/MyApp.js (Adding the form component after the table)**

```React
return (
  <div className="container">
    <Table characterData={characters} removeCharacter={removeOneCharacter} />
    <Form />
  </div>
);
```

##6 - Debugging frontend code on the browser

Some popular browsers such as Chrome and Firefox offer developer tools that allow us to debug our code on the frontend. For instance, if you're on Chrome you can either right-click on a page and select 'inspect' or you can access View -> Developer -> Developer Tools.

I recommend you install these Chrome or Firefox extensions to improve your experience in debugging React code using the browser developer tool: [React dev tools by FB](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) and [the same for Firefox](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/).

If you install this tool, you should be able to open the developer tools in the browser and monitor the `Form` internal state being updated every time you change the input fields (any time you type something in will trigger the onChange event).

##7 - Submitting form data

Before we actually start this next step, it's already a good time to commit current changes. In projects where you collaborate with other developers, make small commits and more frequent pushes a habit. You should run here the same as you did in Step 4.

Cool. The last step is to allow us to actually submit that data and update the parent state. We'll create a function called `updateList()` on `MyApp` that will update the state by taking the existing `characters` and adding the new `person` parameter, using the [ES6 spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax).

**Inside src/MyApp.js (a new function inside the MyApp function)**
```React
function updateList(person) {
  setCharacters([...characters, person]);
}
```

Make sure you defined the function above as a nested function (that function goes inside the MyApp function). And let's make sure we pass that through as a parameter on `Form`. Note that the 'Form' capitalized is our React component.

```React
<Form handleSubmit={updateList} />
```

Now, in `Form`, we'll create an inner function called `submitForm()` that will call the prop handleSubmit, and pass the `Form` state through as the `person` parameter we defined earlier. It will also reset the state to the initial state, to clear the form after submit.

**Inside src/Form.js (a new inner function)**
```React
function submitForm() {
  props.handleSubmit(person);
  setPerson({name: '', job: ''});
}
```

Again, note the function above is a nested function. It should be defined inside the Form function since it uses the 'person' state that is within the Form scope.

And since we're now using handleSubmit prop (code above), we need to make it visible by adding 'props' as a parameter of the Form function.

**src/Form.js (adding the props parameter)**
```React
function Form(props) { ... } //same function just showing we add a parameter 'props'
```

Finally, we'll add a submit button to submit the form. We're using an `onClick` instead of an onSubmit since we're not using the standard submit functionality (i.e., we're not sending the form to a backend component over the network yet). The click will call the `submitForm` we just made.

```React
<input type="button" value="Submit" onClick={submitForm} />
```

Voila! The app is complete! We can add pairs of names and jobs to the table and delete them. Since the `Table` and `TableBody` were already pulling from the MyApp state, it will display properly.

To review what you did, take a moment to write down the resulting component hierarchy, mark what state each component handles, and in what direction data is moved around on each action (typing in the form, submitting form, and deleting rows).

If you followed the previous steps, all you have to do here is to commit and push your last changes. You will do exactly what you did in Step 4 (stage files, commit them, and push to GitHub).

If you reached this point, **good job!** You just completed your first React app with Hooks while following a basic git/github workflow. You used skills, tools, and practices that are valued in our industry.

If you want to discuss anything related to this content, please drop me a line on [Twitter (@BrunoDaSilvaSE)](https://twitter.com/BrunoDaSilvaSE) or a comment below.

I welcome your feedback!