Creating an app with React.js

Huy Do
7 min readJan 18, 2021

Building a todos application by following these order:

1 Create the React app on the terminal. Run the command below and it will create a directory my-app

npx create-react-app app-frontend

2 Start up the React app

Change directory to app-frontend and run npm start . This will open the HTML page

cd app-frontend
npm start

This file App.jsis under the foldermy-app src . This defaults to HTML code and it is rendered on the homepage.

App.js presents as the highest level component in the React app structure. index.jsholds the application’s configuration and dependencies.

3 Set up a component structure

Component structure for todo-app.

App -> (Nav, MainContainer)

MainContainer ->( CreateCard, ToDoCardContainer)

ToDoCardContainer -> ToDoCard

ToDoCard -> ToDoList

We can write components with JavaScrip functions or classes. There are separate folders in the application which are components and containers.

4 Set up the back end using Rails API

We create Card and List models. Cards have many List and List belong to a Card (has many belong to relationship). Using these command lines.

rails new app-api --api
rails g resource card title --no-test-framework
rails g resource list description completed:boolean card:references --no-test-framework

This will create Card and List models in back-end structure without test_unit by using --no-test-framework

We need to install rack-cors (middleware for handling cross-origin resource sharing)

Install active-model-serializer if you are using it to organize your JSON data. Add these gem to the Gemfile and run bundle install in the terminal.

gem 'rack-cors'
gem 'active_model_serializers'
bundle install

5. App component

The App is the highest level which renders MainContainer and Nav children components using JSX (JavasScript Extension). We import components and export App to index.js which will render the entire application

App.js

6 Nav component

We use the function component to display a sample_logo in Nav component

Nav.js
navbar

7 CreateCard component (controlled form)

The MainContainer will be a class component that will hold the logic and state for the application which will be passed down as props to the children components. The MainContainer will fetch request to the back end retrieve created cards, and pass down the cards to TodoContainer to be rendered.

The CreateCard the component will render a form that will take user input and sent it to the back end to create a new instance of Card.

We will use controlled forms (React component handles the form data) instead of uncontrolled forms (DOM handles the data). The component will render the form and hold its own state to keep track of the change of input. The input will be saved inside the component’s state. The CreateCard component’s state will be updated when input is changed.

We set state to an empty string and handleInput function inside the class to handle the changes from the input. The properties of the event only exist when the callback is active. Theevent.persist() references the event and get value and methods inside the function. The event.target.value contains the user’s input value inside the form and this.setState will store that value. The handleInput function will reset the state of the CreateCard component when the input is changed in the form. This function is called by the event listener onChange inside of the rendered form by using this keyword (prefer to parent class which is CreateCard.

CreateCard.js

We pass the input from CreateCardcomponent to the back end to create an Card instance and adding this new card to be rendered under ToDoCardContainer. The MainContainer will be the parent component of CreateCard and ToDoCardContainer components.

8 MainComponent

The MainComponent renders all the cards from the back end on the page. We set the state as an empty array of cards.

MainContainer.js

The crateNewCard function that will pass down as a prop to the CreateCard component. This function fetches input to the back end and receiving the newly created card object and adding the object to the cards array inside the state.

MainContainer.js

We pass the reference to this function as a prop to the CreateCard component when a user submits the form.

We create handleNewCard function to prevent the default action of a submit button and call createNewCard in CreateCard component. We can access the props by using this.props for class components. We pass down props as the function’s argument.

CreateCard.js

9. Fetching data from the back end

The MainContainder renders the ToDoCardContainer The ToDoCardContainer will render each ToDoCard components. We send a fetch request to the back end to get all existing cards. This is asynchronous. It will fail to load and error if we try to render the cards before the fetch request is completed. Therefore we will use the lifecycle methods componentDidMount to run an asynchronous after the initial render of the page. When the fetch request is finished the this.setState will be called and re-render the page with data returned from the fetch request.

MainContainer.js

We will save all the cards instances to the MainContainer state. Then we pass it down to ToDoCardContainer as a prop.

MainContainer.js

10 ToDoCardContainer

The ToDoCardContainer component render all the ToDoCard components. We will use the function component. We map over props.cardsto createToDoCard component for each card object. The ToDoCard component will take card object as the prop which contains title of the card and the todos list. We pass down a unquie card id to kee tract ToDoCard components.

ToDoCardContainer.js

11 ToDoCard

We render new created cards on the page. We return a div container the card object’s tile in ToDoCard with props was passed down from ToDoCardContainer

ToDoCard

We add controlled form on each card to allow the user to add a list item(s) per card. The input state is in TodDoCard the submit function will be passed from the MainContainer. The controlled form is created inside TodoCard.

ToDoCard.js

The addList callback function creates a new List instance using the input and associated card id. We will add new list object to the appropriate card’s array of the list inside the cards state. We find the associated card using the returned list object’s card_id. We concatenate the new list object onto the existing lists array for that card. We map over the existing cards array stored in the state to replace the card object in the with the new, updated card object with the additional list item. We setState of the cards to the new cards array.

MainContainer.js

12 To DoList

We render list per card. We map over the lists for each card which was passed down as a prop to render a ToDoList component. The list item has attribute complete which as set to false by default and set to true when the item is clicked on.

13. Checking off a list item

Ther user can click on the list item and check off the completed list item.We change the List object attributes and keep track inside the MainContainer's state. The function will take List ID and the Card Id as its arguments. We check if clicked list item’s attribute complete to opposite. For example, change it to true if it’s false. We send new state to update by PATCH request

We will update card’s state from the change by using the map method. The list is nested array within the state. We create a new array of updated list then update the card array.

MainContainer.js

The handClickList function will be passed down as the prop to ToDoContainer then to ToDoCard, and last to ToDoList component. Each ToDoList component has the handClickList function as its pro and call the function on each event.

ToDoList.js

We use h3 className value is change by using the ternary operator if list’s attribute is true or false.

References

Another todos app

Rails Generators CLI Cheatsheet

App repo

--

--

Huy Do
0 Followers

Full Stack SE. I love to build beautiful web apps and learn new technologies.