You could be wondering what is so special about React; What we will do is pick up from a previous post about React components and put to practice the theories we discussed following community best practices as always.

As the topic implies, we are going to be building a To-Do application with React. Do not expect any surprises such as managing state with a state management library like Flux or Redux. I promise it will strictly be React. Maybe in following articles we can employ something like Redux but we want to focus on React and make sure everybody is good with React itself.

You don't need much requirements to setup this project because we will make use of CodePen for demos. You can follow the demo or setup a new CodePen pen. You just need to import React and ReactDOM library:

< html > < head > < meta charset = " utf-8 " > < meta name = " viewport " content = " width=device-width " > < title > To-Do </ title > </ head > < body > < div class = " container " > < div id = " container " class = " col-md-8 col-md-offset-2 " > </ div > </ div > < script src = " https://fb.me/react-15.1.0.js " > </ script > < script src = " https://fb.me/react-dom-15.1.0.js " > </ script > </ body > </ html >

ReactDOM is a standalone library that is used to render React components on the DOM.

There are two types of component. These types are not just react-based but can be visualized in any other component-based UI library or framework. They include:

Presentation Component

Container Component

Presentation Component: These are contained components that are responsible for UI. They are composed with JSX and rendered using the render method. The key rule about this type of component is that they are stateless meaning that no state of any sort is needed in such components. Data is kept in sync using props .

If all that a presentation component does is render HTML based on props , then you can use stateless function to define the component rather than classes.

Container Component: This type of component complements presentation component by providing states. It's always the guy at the top of the family tree, making sure that data is coordinated.

You do not necessarily need a state management tool outside of what React provides if what you are building does not have too much nested children and less complex. A To-Do is is simple so we can do with what React offers for now provided we understand how and when to use a presentation or container component

Upgrade Your JS Go from vanilla JavaScript 👉 React

Watch for FREE

It is a recommended practice to have a rough visual representation of what you are about to build. This practice is becomes very important when it comes to component-based designs because it is easier to recognize presentation components.

Your image must not be a clean sketch made with a sketch app. It can just be a pencil work. The most important thing is that you have a visual representation of the task at hand.

From the above diagram, we can fish out our presentation components:

TodoForm : purple

Title: green

TodoList: red

Todo: grey

Todo Form

Functional components (a.k.a stateless components) are good for presentation components because they are simple to manage and reason about when compared with class components.

For that sake, we will create the first presentation component, TodoForm , with a functional component:

const TodoForm = ( { addTodo } ) => { let input ; return ( < div > < input ref = { node => { input = node ; } } / > < button onClick = { ( ) => { addTodo ( input . value ) ; input . value = '' ; } } > + < / button > < / div > ) ; } ;

Functional components just receive props (which we destructured with ES6) as arguments and return JSX to be rendered. TodoForm has just one prop which is a handler that handles the click event for adding a new todo.

The value of the input is passed to the input member variable using React's ref.

Todo & Todo List

These components present the list of to-do. TodoList is a ul element that contains a loop of Todo components (made of li elements`):

const Todo = ( { todo , remove } ) => { return ( < li onClick ( remove ( todo . id ) ) > { todo . text } < / li > ) ; } const TodoList = ( { todos , remove } ) => { const todoNode = todos . map ( ( todo ) => { return ( < Todo todo = { todo } key = { todo . id } remove = { remove } / > ) } ) ; return ( < ul > { todoNode } < / ul > ) ; }

See the Pen AXNJpJ by Chris Nwamba (@christiannwamba) on CodePen.

The remove property is an event handler that will be called when the list item is clicked. The idea is to delete an item when it is clicked. This will be taken care of in the container component.

The only way the remove property can be passed to it's to the Todo component is via it's parent (not grand-parent). For this sake, in as much as the container component that will own TodoList should handle item removal, we still have to pass down the handler from grand-parent to grand-child through the parent.

This is a common challenge that you will encounter in a nested component when building React applications. If the nesting is going to be deep, it is advised you use container components to split the hierarchy.

Title

The title component just shows the title of the application:

const Title = ( ) => { return ( < div > < div > < h1 > to - do < / h1 > < / div > < / div > ) ; }

This will eventually become the heart of this application by regulating props and managing state among the presentation components. We already have a form and a list that are independent on each other but we need to do some tying together where needed.

window . id = 0 ; class TodoApp extends React . Component { constructor ( props ) { super ( props ) ; this . state = { data : [ ] } } addTodo ( val ) { const todo = { text : val , id : window . id ++ } this . state . data . push ( todo ) ; this . setState ( { data : this . state . data } ) ; } handleRemove ( id ) { const remainder = this . state . data . filter ( ( todo ) => { if ( todo . id !== id ) return todo ; } ) ; this . setState ( { data : remainder } ) ; } render ( ) { return ( < div > < Title / > < TodoForm addTodo = { this . addTodo . bind ( this ) } / > < TodoList todos = { this . state . data } remove = { this . handleRemove . bind ( this ) } / > < / div > ) ; } }

View CodePen Progress

We first setup the component's constructor by passing props to the parent class and setting the initial state of our application.

Next we create handlers for adding and removing todo which the events are fired in TodoForm component and Todo component respectively. setState method is used to update the application state at any point.

As usual, we render the JSX passing in our props which will be received by the the child components.

We have been rendering our demo components to the browser without discussing how but can be seen in the CodePen samples. React abstracts rendering to a different library called ReactDOM which takes your app's root component and renders it on a provided DOM using an exposed render method:

ReactDOM . render ( < TodoApp / > , document . getElementById ( 'container' ) ) ;

The first argument is the component to be rendered and the second argument is the DOM element to render on.

We could step up our game by working with a HTTP server rather than just a simple local array. We do not have to bear the weight of jQuery to make HTTP request, rather we can make use of a smaller library like Axios.

< script src = " https://npmcdn.com/axios/dist/axios.min.js " > </ script >

React lifecycle methods help you hook into React process and perform some actions. An example is doing something once a component is ready. This is done in the componentDidMount lifecycle method. Lifecycle methods are just like normal class methods and cannot be used in a stateless component.

class TodoApp extends React . Component { constructor ( props ) { super ( props ) ; this . state = { data : [ ] } this . apiUrl = 'https://57b1924b46b57d1100a3c3f8.mockapi.io/api/todos' } componentDidMount ( ) { axios . get ( this . apiUrl ) . then ( ( res ) => { this . setState ( { data : res . data } ) ; } ) ; } }

Mock API is a good mock backend for building frontend apps that needs to consume an API in the future. We store the API URL provided by Mock API as a class property so it can be accessed by different members of the class just as the componentDidMount lifecycle method is. Once there is a response and the promise resolves, we update the state using:

this . setState ( )

The add and remove methods now works with the API but also optimized for better user experience. We do not have to reload data when there is new todo, we just push to the existing array. Same with remove:

addTodo ( val ) { const todo = { text : val } axios . post ( this . apiUrl , todo ) . then ( ( res ) => { this . state . data . push ( res . data ) ; this . setState ( { data : this . state . data } ) ; } ) ; } handleRemove ( id ) { const remainder = this . state . data . filter ( ( todo ) => { if ( todo . id !== id ) return todo ; } ) ; axios . delete ( this . apiUrl + '/' + id ) . then ( ( res ) => { this . setState ( { data : remainder } ) ; } ) }

We could keep track of the total items in our To-Do with the Title component. This one is easy, place a property on the Title component to store the count and pass down the computed count from TodoApp:

const Title = ( { todoCount } ) => { return ( < div > < div > < h1 > to - do ( { todoCount } ) < / h1 > < / div > < / div > ) ; } class TodoApp extends React . Component { render ( ) { return ( < div > < Title todoCount = { this . state . data . length } / > < ! -- ... -- > < / div > ) ; } }

The app works as expected but not pretty enough for consumption. Bootstrap can take care of that. The following CodePen demo shows some updates made to change the look of the app:

See the Pen PzVyRm by Chris Nwamba (@christiannwamba) on CodePen.

We violated minor best practices for brevity but most importantly, you get the idea of how to build a React app following community recommended patterns.

As I mentioned earlier, you don't need to use a state management library in React applications if your application is simpler. Anytime you have doubt if you need them or not, then you don't need them. (YAGNI).

On the other hand, expect an article on Redux from Scotch soon.

Like this article? Follow @codebeast on Twitter