DEV Community

Cover image for React Hooks from Scratch - Part 1
varunprashar5
varunprashar5

Posted on • Originally published at techbrainshub.com

React Hooks from Scratch - Part 1

Hooks allows you to use state in your functional component. They are introduced in React 16.8.0 as a new feature.

Few benefits of Hooks:
  • Isolate stateful logic in a function and makes it easier to test
  • Lets you reuse stateful components within different components
  • Avoiding ES6 classes and providing alternatives to lifecycle events within the function itself.

React has introduced multiple hooks:

Basic Hooks

  • useState
  • useEffect
  • useContext

Additional Hooks

  • useReducer
  • useCallback
  • useMemo
  • useRef

and many more.

In this part series we will be focusing on one primary hook which is mainly used to manage states i.e. useState

useState(): This is a hook which is used to add local state to the functional component. Like earlier functional components were stateless and were only intended to show data (as presentational components) being passed data using props by container components.

Const [name,setName] = useState("Varun");

useState returns two things:

  • State (“name” in our case with initial state as "varun")
  • Function to update that state (in our case "setName")

Above we are using the ES6 concept named destructuring pattern to get “name” & “setName” as constants.

If you don’t want to use this pattern then you can do it this way:

const stateInfo = useState("Varun");

Const name = stateInfo[0];

Const setName = stateInfo[1];

So we can directly use {name} inside our return method in the functional component to print its name.

To update this name we can directly call this method:

setName("Vippy");

This is what we usually do via setState in class component as:

this.setState({name:"Vippy"});

Examples of same functionality via class component & Hooks:

Class Component Example: ClassExample.js

import React, { Component } from "react";
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Typography from "@material-ui/core/Typography";

export default class ClassExample extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "Varun"
    };
  }
  render() {
    return (
      <Card>
        <CardContent>
          <Typography gutterBottom variant="h5">
            Class Example
          </Typography>
          My name is: {this.state.name}
          <p>
            <Button
              variant="contained"
              color="primary"
              onClick={() => {
                this.setState({ name: "Vippy" });
              }}
            >
              Change Name
            </Button>
          </p>
        </CardContent>
      </Card>
    );
  }
}

Explanation:

  • In above we created a local state of the component via “this.state” inside the constructor with property named “name” as “Varun” (as default value)
  • Inside the render we showed the state value via “this.state.name”
  • On button click handler we are changing the name by calling this.setState({“name”:”Vippy”});

Hook Example: UsingHooks.js

import React, { useState } from "react";
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Typography from "@material-ui/core/Typography";

export default function UsingHooks() {
  const [name, setName] = useState("Varun");
  return (
    <Card>
      <CardContent>
        <Typography gutterBottom variant="h5">
          Hook Example
        </Typography>
        My name is: {name}
        <p>
          <Button
            variant="contained"
            color="primary"
            onClick={() => {
              setName("Hardeep");
            }}
          >
            Change Name (Hook)
          </Button>
        </p>
      </CardContent>
    </Card>
  );
}

Explanation:

  • Here we are using local state in our functional component via a “hook” named “useState”
  • We set the default value of as useState(“Varun”)
  • We can access the state value by “name” and set its value by calling “setName()”
  • In return you can see that we have an “onClick” handler which is updating the name from “Varun” to “Hardeep” via “setName()” method.

If you want to run this application and want to see both of the versions on a single page. You can use the following code:

App.js

import React from "react";
import Container from "@material-ui/core/Container";
import CssBaseline from "@material-ui/core/CssBaseline";
import Divider from "@material-ui/core/Divider";

import ClassComponent from "./ClassExample";
import UsingHooks from "./UsingHooks";
import UsingHooksExtended from "./UsingHooksExtended";

import "./styles.css";

export default function App() {
  return (
    <React.Fragment>
      <CssBaseline />
      <Container maxWidth="sm">
        <ClassComponent />
        <Divider />
        <UsingHooks />
      </Container>
    </React.Fragment>
  );
}

More about useState:
In the example above, We have used only a single value as a state which is “name” in our case.

But it is not only limited to single state variable, We can define multiple state variables inside our function as:

Const [name,setName] = useState("Varun"); //used string as initial state

Const [age,setAge] = useState(27); //used number as initial state

So this way now we can use two state variables named "name" & "age".

As of now, We only used single value in our useState but it is not limited to single value only.

We can have a state value as: String, Number, Array, Object.

So this way it will help us to store multiple values in our single state variable.

Example:

As String:
Const [name,setName] = useState("Varun");

As Object:
const [ person, updatePerson ] = useState({ name: "Varun", age: 27 });

As Array of Object:
const [ todos, setTodos ] = useState([ { text: "todo 1" }, { text: "todo 2" } ]);

Example: UsingHooksExtended.js

import React, { useState } from "react";
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Divider from "@material-ui/core/Divider";
import Typography from "@material-ui/core/Typography";

export default function UsingHooks() {
  const [name, setName] = useState("Varun");
  const [age, setAge] = useState(27);
  const [person, updatePerson] = useState({ name: "Varun", age: 27 });
  const [todos, setTodos] = useState([{ text: "todo 1" }, { text: "todo 2" }]);

  return (
    <React.Fragment>
      <Card>
        <CardContent>
          <Typography gutterBottom variant="h5">
            Hook using String & Number
          </Typography>
          Name: {name} <br />
          Age: {age} <br />
          <br />
          <Button
            variant="contained"
            color="primary"
            onClick={() => {
              setName("Hardeep");
              setAge(29);
            }}
          >
            Change Name
          </Button>
        </CardContent>
      </Card>
      <Divider />

      <Card>
        <CardContent>
          <Typography gutterBottom variant="h5">
            Hook using Object
          </Typography>
          <div>Person state as Object:</div>
          Name: {person.name}
          <br />
          Age: {person.age}
          <br />
          <br />
          <Button
            variant="contained"
            color="primary"
            onClick={() => {
              updatePerson({ name: "Hardeep", age: 29 });
            }}
          >
            Change Name & Age
          </Button>
        </CardContent>
      </Card>
      <Divider />

      <Card>
        <CardContent>
          <Typography gutterBottom variant="h5">
            Hook using Array of Objects
          </Typography>
          Todos state as Array of Objects:
          <ul>
            {todos.map(todo => {
              return <li>{todo.text}</li>;
            })}
          </ul>
          <br />
          <Button
            variant="contained"
            color="primary"
            onClick={() => {
              setTodos([...todos, { text: "todo 3" }]);
            }}
          >
            Add Todo
          </Button>
        </CardContent>
      </Card>
    </React.Fragment>
  );
}

Explanation:

  • Here we have used multiple form of data we can set via useState i.e. single value, array, object
  • Person is a state which has data in the form of object
  • Todos is a state constant which is array of objects
  • Clicking on different buttons are making changes to their respective state variable

Simple Use Case of Hook:
It can be used if you have a functional component (which is stateless) and you want to use state inside it. So now instead of converting that function to a class component just include a "useState" hook inside that functional component.

Here is the CodeSandBox if you wanna play around !

I hope this might be helpful, feel free to reach me out in any case.

Top comments (0)