DEV Community

Cover image for React Hooks Tutorial <Beginner Level>
Ruiru11
Ruiru11

Posted on • Originally published at ruiru.hashnode.dev

React Hooks Tutorial <Beginner Level>

React Hooks Tutorial Beginner Level

Purpose of this Blog:

  • To explain how React Hooks work
  • Build a simple Application to help in understanding

What we are Building

A simple Todo app where we can add todo items, mark todo items as complete and delete todo item

Get started

React Hooks are a new addition in react version 16.8.0, we are going to learn about the 'UseState' Hook. The biggest addition that Hooks add is giving us the ability to use state in function based components we all know this was not possible before. This hook lets you have an internal state inside a functional Component

Lets create a React app

  • cd into your Preferred directory
  • in the command line run
$ npx create-react-app react-hook-tutorial
Enter fullscreen mode Exit fullscreen mode
  • Then we cd into the above
cd react-hook-tutorial
Enter fullscreen mode Exit fullscreen mode
  • Open your code editor and let us delete the existing code in App.js and App.css

lets write code.

In this tutorial, We are going to use mock Data our objective will be to display the data. We will be using semantic UI for styling I am using the CDN

  • In the index.html file add
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.11.8/semantic.min.css"/>
Enter fullscreen mode Exit fullscreen mode

In our App.js file Lets add this

import React, { useState } from "react";
import "./App.css";

function App() {
 //create your dummy data
 //todos is where we have our data
 //updateTodo is what we use to update 'state' by using the useState method we import from react
  const [todos, updateTodo] = useState([
    {
      item: "learn react hooks",
      completed: false
    },
    {
      item: "create a simple app to illustarate the above",
      completed: false
    },
    {
      item: "push to git hub",
      completed: false
    }
  ]);

//we loop through the todos 
//Notice we have a Todo component in the return statement we will have to create that
  return (
    <div id="role" role="list" className="ui divided relaxed list">
      <div role="listitem" className="item">
        {todos.map((todo, index) => (
          <Todo
            key={index}
            index={index}
            todo={todo}
          />
        ))}
      </div>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Now we create a components folder inside the src folder, create a todo.js file

  • add the following
import React from "react";

//pass props this are from the App.js file
const Todo = ({ todo, index, }) => {
  return (
    <div
      role="list"
      className="ui divided middle aligned list"
    >
      <div role="listitem" className="item">
        <div className="right floated content">
        </div>
        <i aria-hidden="true" className="spinner loading icon" />
        <i aria-hidden="true" className="certificate loading icon" />
        <i aria-hidden="true" className="asterisk loading icon" />
        <div className="content">{todo.item}</div>
      </div>
    </div>
  );
};

export default Todo;
Enter fullscreen mode Exit fullscreen mode

Now we have our Todo component which we need to use in our App.js file

  • Add this in our App.js file
import Todo from "./components/todo";
Enter fullscreen mode Exit fullscreen mode

Open your browser and you should have something similar to what we have. You can use any image for your background image

Screenshot 2019-06-03 at 11.36.38.png

We have been able to display our todos. We will now start using the useState Hook. We want to be able to add a new todo item. In the components, folder create a file addTodoForm.js

  • Add the following code
import React, { useState } from "react";

//create a AddTodoForm component
function AddTodoForm({ addTodo }) {
//we useState to set the value on the onchange function
const [value, setValue] = useState("");

  const handleSubmit = e => {
    e.preventDefault();
    if (!value) return;
    addTodo(value);
    setValue("");
  };
// return a form to handle our input
  return (
    <form className="ui success form">
      <div className="field">
        <label>Add Todo Item</label>
        <div className="ui input">
          <input
            type="text"
            placeholder="Add todo item"
            value={value}
            onChange={e => setValue(e.target.value)}
          />
        </div>
        <button onClick={handleSubmit} className="ui button">
          Add
        </button>
      </div>
    </form>
  );
}

export default AddTodoForm;
Enter fullscreen mode Exit fullscreen mode

The above code only gives us a form we are not able to add a todo item yet. So at this point, we need to write the addTodo function that will make this possible. Remember we passed it as a prop in the component we have created above.

  • Add the following in the App.js file
//the function takes in an item argument
  const addTodo = item => {
  //here we use the spread operator to copy everything we have in the todos array 
 //we can now manipulate the NewTodos variable as it contains data similar to what we have in the todos array
    const newTodos = [...todos, { item }];
   //now we use the updateTodo method to actually update the Todos list
    updateTodo(newTodos);
  };
Enter fullscreen mode Exit fullscreen mode

We will still not be able to add a todo item, to make this happen we need to import the addTodoForm in our App.js file

  • Open App .js and lets add
import AddTodoForm from "./components/addTodoForm";
Enter fullscreen mode Exit fullscreen mode
  • lastly add this
 <AddTodoForm addTodo={addTodo} />
Enter fullscreen mode Exit fullscreen mode

Now our App.js file Looks like this

import React, { useState } from "react";
import "./App.css";
import Todo from "./components/todo";
import AddTodoForm from "./components/addTodoForm";

function App() {
 //create your dummy data
 //todos is where we have our data
 //updateTodo is what we use to update 'state' by using the useState method we import from react
  const [todos, updateTodo] = useState([
    {
      item: "learn react hooks",
      completed: false
    },
    {
      item: "create a simple app to illustarate the above",
      completed: false
    },
    {
      item: "push to git hub",
      completed: false
    }
  ]);

//we loop through the todos 
//Notice we have a Todo component in the return statement we will have to create that
  return (
    <div id="role" role="list" className="ui divided relaxed list">
      <div role="listitem" className="item">
        {todos.map((todo, index) => (
          <Todo
            key={index}
            index={index}
            todo={todo}
          />
        ))}
     <AddTodoForm addTodo={addTodo} />
      </div>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

At this point, we should have a form to add a new todo item. You should have something similar to what we have below.
Screenshot 2019-06-03 at 12.00.57.png

We now need two buttons one to mark a todo as complete and another to delete a todo item

  • Open the todo.js file and add the following
          <button onClick={() => completTodo(index)} className="ui button">
            Complete
          </button>
          <button onClick={() => deleteTodo(index)} className="ui button">
            Delete
          </button>
Enter fullscreen mode Exit fullscreen mode

The todo.js file should now look like this

import React from "react";

const Todo = ({ todo, index }) => {
  return (
    <div
      id="main"
      style={{ textDecoration: todo.completed ? "line-through" : "" }}
      role="list"
      className="ui divided middle aligned list"
    >
      <div role="listitem" className="item">
        <div className="right floated content">
          <button onClick={() => completTodo(index)} className="ui button">
            Complete
          </button>
          <button onClick={() => deleteTodo(index)} className="ui button">
            Delete
          </button>
        </div>
        <i aria-hidden="true" className="spinner loading icon" />
        <i aria-hidden="true" className="certificate loading icon" />
        <i aria-hidden="true" className="asterisk loading icon" />
        <div className="content">{todo.item}</div>
      </div>
    </div>
  );
};

export default Todo;
Enter fullscreen mode Exit fullscreen mode

Notice in both the complete button and delete button we called a completeTodo function and a deleteTodo function respectively, these functions don't exist so we have to create them

  • Open App.js and add the following block of code
//the function takes an index parameter  so that we are able to know the todo we are marking as complete  
const completTodo = index => {
    const NewTodos = [...todos];
    NewTodos[index].completed = true;
    updateTodo(NewTodos);
  };

//the function takes an index parameter so that we know the todo item we are deleting
  const deleteTodo = index => {
    const NewTodos = [...todos];
    NewTodos.splice(index, 1);
    updateTodo(NewTodos);
  };

Enter fullscreen mode Exit fullscreen mode

Then add this in the App.js file

  completTodo={completTodo}
   deleteTodo={deleteTodo}
Enter fullscreen mode Exit fullscreen mode

our App .js file now looks like this

import React, { useState } from "react";
import "./App.css";
import AddTodoForm from "./components/addTodoForm";
import Todo from "./components/todo";
import HeaderDiv from "./components/header";

function App() {
  const [todos, updateTodo] = useState([
    {
      item: "learn react hooks",
      completed: false
    },
    {
      item: "create a simple app to illustarate the above",
      completed: false
    },
    {
      item: "push to git hub",
      completed: false
    }
  ]);

  const addTodo = item => {
    const newTodos = [...todos, { item }];
    updateTodo(newTodos);
  };

  const completTodo = index => {
    const NewTodos = [...todos];
    NewTodos[index].completed = true;
    updateTodo(NewTodos);
  };

  const deleteTodo = index => {
    const NewTodos = [...todos];
    NewTodos.splice(index, 1);
    updateTodo(NewTodos);
  };
  return (
    <div id="role" role="list" className="ui divided relaxed list">
      <HeaderDiv />
      <div role="listitem" className="item">
        {todos.map((todo, index) => (
          <Todo
            key={index}
            index={index}
            todo={todo}
            completTodo={completTodo}
            deleteTodo={deleteTodo}
          />
        ))}
        <AddTodoForm addTodo={addTodo} />
      </div>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Lastly, to be able to use the two functions we need to pass them as props in the todo.js file. Open it and add this

const Todo = ({ todo, index, completTodo, deleteTodo })
Enter fullscreen mode Exit fullscreen mode

Now the todo.js file looks like this

import React from "react";

const Todo = ({ todo, index, completTodo, deleteTodo }) => {
  var buttonText = todo.completed ? "completed" : "complete";
  return (
    <div
      id="main"
      style={{ textDecoration: todo.completed ? "line-through" : "" }}
      role="list"
      className="ui divided middle aligned list"
    >
      <div role="listitem" className="item">
        <div className="right floated content">
          <button onClick={() => completTodo(index)} className="ui button">
            {buttonText}
          </button>
          <button onClick={() => deleteTodo(index)} className="ui button">
            Delete
          </button>
        </div>
        <i aria-hidden="true" className="spinner loading icon" />
        <i aria-hidden="true" className="certificate loading icon" />
        <i aria-hidden="true" className="asterisk loading icon" />
        <div className="content">{todo.item}</div>
      </div>
    </div>
  );
};

export default Todo;
Enter fullscreen mode Exit fullscreen mode

Notice I introduced a buttonText variable this is just to make the text in the button dynamic that is if you click on the button the text becomes completed

Screenshot 2019-06-03 at 14.12.17.png

Lastly we will add an about section
In the components, folder create a file header.js and add the following block of code

import React from "react";

function HeaderDiv() {
  return (
    <div className="ui message">
      <div className="header">About</div>
      <p>
        This is a simple application to help you level up on React Hooks. There is no data persistence as this will be available in the next tutorial.
      </p>
      <p>
        Below are links to the developers LinkedIn and Github accounts
        respectively
      </p>
      <a href="url">
        <button className="ui linkedin button">
          <i aria-hidden="true" className="linkedin icon" /> LinkedIn
        </button>
      </a>
      <a href="url">
        <button className="ui github button">
          <i aria-hidden="true" className="github icon" /> github
        </button>
      </a>
    </div>
  );
}

export default HeaderDiv;

Enter fullscreen mode Exit fullscreen mode

We then bring in the component, open App.js and add the following import statement

import HeaderDiv from "./components/header";
Enter fullscreen mode Exit fullscreen mode

Now our App.js file should look like this

import React, { useState } from "react";
import "./App.css";
import AddTodoForm from "./components/addTodoForm";
import Todo from "./components/todo";
import HeaderDiv from "./components/header";

function App() {
  const [todos, updateTodo] = useState([
    {
      item: "learn react hooks",
      completed: false
    },
    {
      item: "create a simple app to illustarate the above",
      completed: false
    },
    {
      item: "push to git hub",
      completed: false
    }
  ]);

  const addTodo = item => {
    const newTodos = [...todos, { item }];
    updateTodo(newTodos);
  };

  const completTodo = index => {
    const NewTodos = [...todos];
    NewTodos[index].completed = true;
    updateTodo(NewTodos);
  };

  const deleteTodo = index => {
    const NewTodos = [...todos];
    NewTodos.splice(index, 1);
    updateTodo(NewTodos);
  };
  return (
    <div id="role" role="list" className="ui divided relaxed list">
      <HeaderDiv />
      <div role="listitem" className="item">
        {todos.map((todo, index) => (
          <Todo
            key={index}
            index={index}
            todo={todo}
            completTodo={completTodo}
            deleteTodo={deleteTodo}
          />
        ))}
        <AddTodoForm addTodo={addTodo} />
      </div>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

This is how the product looks like

Screenshot 2019-06-03 at 01.49.08.png

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.