React Hands-on, Part 2

Dec 29th 2019 by Mattes Wieben

First React application: Hands on (Part 2)

Introduction

Last week, we started building a Task-Creation-Application for the Super Heroes of Coding Valley. We set the project up and created a static version of the application. There is no state to the application yet and no functionality either. That’s what we’re going to change today. But we’re only going to implement the client-site application. No Backend-Services so far to keep everything simple.

In a couple of weeks, after finishing the Front-end-JS Tutorials, I’m going to write about backend-development, also with JavaScript, using Node.js. (Bad marketers would encourage you to follow this blog to stay up to date with those changes, but that’s too much of a sell out. So I won’t)

Recap

Let’s quickly recap the steps, we did last week. First we set the project up, inspected the folder structure and added the project to the IDE. After that we took a look at the UI to develop and broke that down into separate, small parts that are sized to be developed as React-Components. Lastly, we implemented those small components and sticked them together to get this UI:

UI Vision

That’s the state of code we are at right now. Recap done. Let’s go on and make our application do something.

Step 3: Identify the state

For making our application do something, we need to identify the state (in case you don't know about state yet, this will help). The state should include the absolute minimum of mutable variables. Everything that can be derived from that minimum should be computed based on the state whenever necessary. That avoids bugs slipping in.

Go ahead and try to make a list of all the data this application needs to store. 

Pooh - Think

Here's my list:

Task-Creation

  1. The content of the name-input

  2. The content of the description-text area

  3. The state of the favorite-hero dropdown

  4. The state of the severity-radio button group

  5. The newly created items

Task-Search

  1. The initial list of tasks

  2. The extended list of tasks (initial + newly created items)

  3. The filtered list of tasks

  4. The content of the search field

  5. The state of the checkbox

Now we have all the data. We should try to minimise that as much as possible. Here are some helper questions, we can check for every part of the data:

  1. Is the given data passed from a parent via props? → If so, probably not state

  2. Does the data stay remain unchanged over time? → If so, probably not state

  3. Can we compute the data based on other variables (state or props)? → If so, probably not state

After applying those tests to all the data we found before, we come up with to following:

Task-Creation

  1. The content of the name-input

  2. The content of the description-text area

  3. The state of the favorite-hero dropdown

  4. The state of the severity-radio button group

  5. The newly created items

This is pretty easy, the whole set of data, we identified are user-inputs. That means, they are definitely not passed in by a parent component, they may change over time and they cannot be computed. So, everything is part of the state.

Task-Search

  1. The content of the search field

  2. The state of the checkbox

Here, we can see some changes. Firstly, the initial list of tasks isn’t part of the state, because it does not change over time. Secondly, the extended list of tasks isn’t part of the state, because it can be computed based on the initial list and the newly created items. Lastly, the the filtered list of tasks isn’t state, because it can be computed based on the initial list, the newly created items and the filter parameters.

And that’s it. We identified our minimal set of state.

Step 4: Identify where the state should live

Now that we identified the minimal set of state, we need to figure out, where it should live. To do that, we need to evaluate each part of the state individually. For each of these parts, we need to check which components need that information to render.

As soon as we know that, we need to find the closest common parent-component. That’s usually where the state should live. We have to keep in mind, that this component will be the owner of the state and it won’t be changed anywhere but there.

In some cases, it might also be useful to add components into the hierarchy for the sole purpose of grouping child-components together that share a part of the state. We’ll do that in the next state.

Let’s do this for every identified part of the app’s state:

  1. The content of the name-input: Only necessary in the TaskCreationForm

  2. The content of the description-text area: Only necessary in the TaskCreationForm

  3. The state of the favorite-hero dropdown: Only necessary in the TaskCreationForm

  4. The state of the severity-radio button group: Only necessary in the TaskCreationForm

So far so easy, now some parts of the state, that are used in more than one component:

  1. The newly created items: 

    1. Created in TaskCreationForm

    2. Shown in TaskTable

→ Should live in closest common ancestor.

→ There is none, except the AppComponent. We don’t want to mess up that component. Therefore we create a new for the sole purpose of holding that shared state.

  1. The content of the search field

    1. Inserted in Searchbar

    2. Needed to compute the filtered TaskList in TaskTable

→ Should live in closest common ancestor.

→ There is the AppContainer we created in the previous step

  1. The state of the checkbox

    1. Modified in Searchbar

    2. Needed to compute the filtered TaskList in TaskTable

→ Should live in closest common ancestor.

→ There is the AppContainer we created in step 5.

These are the code changes:

  1. We simplified the App.js and extracted everything but the style definition into the AppContainer Component.

React 3, Bild 1

2. The AppContainer is a class component which holds all the elements that previously had been in the App.js. Here we’ll store the shared state in the next step.

React 3, Bild 2

And finally, let’s add this to our application.

Initial List of Tasks

We’re going to start by extracting the hard coded initial task list into an array and put that into the index.js file. We said it’s not part of the state. Therefore, we expect it as an input from somewhere else.

That array should be assumed as an input of a backend service. Since we don’t build that right now, that’s the closest assumption I could come up with. Here are the changes to the index.js:

React 3 Bild 3

Also, we pass the tasks from the App into the AppContainer:

React 3 Bild 4

and from the AppContainer into the TaskTable:

React 3 Bild 5

In the TaskTable-Component, we use this array from the props to dynamically generate the elements, we want to be shown.

React 3 Bild 6

This method is a neat example of the power given to you by React’s approach of adding tags into your usual JavaScript environment. In just a couple of lines of code we dynamically build a list with sub-headers and items for each subheader.

If you have a look at the developer-console, you’ll see an error. Don’t worry about that, we’ll fix that now. The problem is, that React requires us to give each element of a list a unique key. React will use this key to evaluate which items need to be change while rerendering. Therefore, we add a unique key to the SubHeaders:

React 3 Bild 15

and to the list items:

React 3 Bild 16

We assume here, that the task’s title is unique, which, in fact, it is not. For simplicity, let’s assume it was.

Assumption

The necessity might becomes clearer after reading this article.

Searchbar

Now let’s lift the Searchbar-Component’s state (the default values) up into the AppContainer. “Lifting state up” is a term you’ll frequently get across when developing React applications.

Lifting

It describes the process of extracting the state of a component into a parent component, because it is needed by other child-components as well. That’s just what we’re doing. Since the TaskTable needs the SearchBar’s state we’re lifting it up into it’s common parent, the AppContainer:

Therefore, we define the state in the AppContainer:

React 3 Bild 7

pass the necessary parts of the state as props into the SearchBar:

React 3 Bild 8

and use the props in the SearchBar to show the value:

React 3 Bild 9

We removed the local state and used the initial values from the props. Now we can go ahead and change the default values in the AppContainer’s state and we’ll see, that the default values are changing.

Final things:

  • We add an empty array to the state of the AppContainer for the newly created Items.

TaskCreationForm

The state of the input values are only of relevance to the TaskCreationForm. Therefore we can use this component to declare the component’s states:

React 3 Bild 10

And while we’re here, let’s define simple change-handlers for the inputs and a click-handler for the add button:

React 3 Bild 11

Finally, let’s add the state and the handlers to our components:

React 3 Bild 12

Also, we need to use the state and the functions inside the Hero-Selector:

React 3 Bild 13

And the Severity-Selector:

React 3 Bild 14

Here’s how your code should look like after adding the state to the application.

Step 5: Add inverse Dataflow

By now, we implemented the state, but our application still doesn’t work properly. The reason is, that the inverse Dataflow isn’t implemented yet.

Events aren’t correctly routed to the components in which the state lives to handle them. Let’s go ahead and fix this. Afterwards our application will be done.

  1. Add handlers and pass them

    1. setState instead of directly assigning

    React 3 Bild 17React 3 Bild 18
  2. Use the handlers in the TaskTable

React 3 Bild 19

3. Fails → bind this

React 3 Bild 20

4. Addition to render-method

React 3 Bild 21React 3 Bild 22

Isn’t that awesome? We only changed code in the Component where the state lives and all children act accordingly. THAT’S what we want for writing maintainable code 😍

Awesome

Now let’s implement the last pieces of code to enable users to create tasks.

  1. Update state in ClickHandlers

React 3 Bild 23

2. Bind them

React 3 Bild 24

3. Change values of MenuItems

React 3 Bild 25

4. Create the new task in the ButtonClickHandler

React 3 Bild 26

5. Pass it to the AppContainer and add to newlyCreated Array (define handler, bind it, pass as prop, use in TaskCreationForm)

React 3 Bild 27React 3 Bild 28React 3 Bild 29React 3 Bild 30

You can find the final result of this application in my GitHub. Check it out and create as many tasks as the Coding Valley Super Heros can handle.

There is one optional thing left to do. We add a description for each task, but it’s shown nowhere. When a user clicks a task in the TaskTable the description should be shown below the TaskTable. Go ahead and practice your React skills implementing this function on your own. I’ll happily review every solution you send to me 😊

Roundup

That’s it for today! As always, thank you so much for reading. I hope, you had a good time doing so and learned a thing or two. If you liked the content, subscribe stay tuned for the next week. Also, please feel free to leave a comment to express your thoughts, ask a question, tell me, what I did wrong or just say hi 👋 I might ‘hi’ back.

Share this post