React Hooks from Scratch - Part 1

React Hooks from Scratch - Part 1

Hooks allow 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 that 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 the 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 the 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 the above, we created a local state of the component via “this.state” inside the constructor with a property named “name” as “Varun” (as the 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 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 that is updating the name from “Varun” to “Hardeep” via the “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 the 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

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 a single value in our useState but it is not limited to a 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 forms of data we can set via useState i.e. single value, array, object
  • The person is a state which has data in the form of an object
  • Todos is a state constant which is an 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 the 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.




Thanks for sharing, the article was very useful and informative 👍

Yeah, it's something new that react come up with..but although it's also change the state for those which is not changed...so also need to keep it by spread..👍

To view or add a comment, sign in

Others also viewed

Explore content categories