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.js
is 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.js
holds 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
6 Nav component
We use the function component to display a sample_logo in Nav
component
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.
We pass the input from CreateCard
component 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.
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.
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.
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.
We will save all the cards instances to the MainContainer
state. Then we pass it down to ToDoCardContainer
as a prop.
10 ToDoCardContainer
The ToDoCardContainer
component render all the ToDoCard
components. We will use the function component. We map over props.cards
to 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.
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
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
.
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.
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.
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.
We use h3
className value is change by using the ternary operator if list’s attribute is true or false.
References