DEV Community

Cover image for Why We Use Custom Hooks.
Anish Ali
Anish Ali

Posted on • Originally published at Medium

Why We Use Custom Hooks.

Why We Use Custom Hooks.

In this article we will answer every question in your thoughts so be ready and lets get started. Lets understand how custom hooks works and how actually hooks works in practice.

We see a lot of things can be done by custom hooks but we don’t know why, when & where to use it?

What is Custom Hook.

Custom hooks in React are reusable JavaScript functions that allow you to extract and share stateful logic between components.

There are alot of stuff that we have to do in our apps that react didn’t give us out of the box so they introduced the Custom Hooks concept to make our own.
Without wasting anytime let’s go deep into this.

tip: First of all not all hooks or custom-hooks return [value, setValue] type of thing this is just and array useState return with 0 and 1 index and in 0 index it return the value and in 1 index it returns the function to change 0 index value

const useStateOwn = (defaultValue:any) => { 
    let state = defaultValue
    const setChangeState = (changeValue:any) => { 
        state = changeValue
    } 
    return [state,setChangeState] 
}
Enter fullscreen mode Exit fullscreen mode

This is a simplified example of how useState works internally. It’s not React’s real implementation, just for your understanding.

Devider

Now let’s understand how to create custom hook & later we understand when and why we should use this hook.

This is the basic of the basic custom hook.

export function useCustomHook() {
 return 'some text return'
}
Enter fullscreen mode Exit fullscreen mode

This is the basic custom hook. It may looks like a function but it’s not.
Hooks are used inside Functional Components & Custom Hooks not anywhere else. Wait what did i just say, custom hooks are used inside custom hooks ?

Hooks usecase

Will explain you later. First let’s just find the difference between custom hooks and functions.

Let’s say you have 2 functions

function foo () {
    return 10
} 
Enter fullscreen mode Exit fullscreen mode
function bar () {
    // we can all another function here 
    const fooValue = foo(); // just like this one
    return fooValue 
}
Enter fullscreen mode Exit fullscreen mode

We can call 1 function into another function as you see the above, but the problem relies with hooks / custom hooks is that we cannot call custom hooks inside of the functions.

Devider

Let me just create an example of that as well for better understanding.

function getDataCurrent (){
    const currentData = useCustomHook() // just like this one 
    // because using this in function will give us this error

    /*
        React Hook "useCustomHook" is called in function "getDataCurrent"
        that is neither a React function component 
        nor a custom React Hook function. React component names must 
        start with an uppercase letter. 
        React Hook names must start with the 
        word "use".eslintreact-hooks/rules-of-hooks 
    */
}
// as you see the error clearly most of the things got clear 
Enter fullscreen mode Exit fullscreen mode

There is few rules that you have to remember and that’s it.

  1. it must start with “use” string
  2. it cannot be call inside an function or nested function
  3. any open return statement will be use after hooks.

Rules

Now that we know the basic of How Custom hook is created and when / where is should be created.

Devider

Let’s move on to the usecase of custom hooks.

function useTestCustomHook () {
    // you can call whatever inside a custom hook.
    // useCustomHook() ! a custom hook
    // test() ! a function 
    // <Page/> ! a Component
}
Enter fullscreen mode Exit fullscreen mode

In this example we created custom hook with a name “useTestCustomHook” but as you see in the comments i’ve clearly mention that custom hook will call anything inside of it. Just because it’s an client side code so you can use anything of clientside inside of it.

You can doo unlimited stuff with custom hooks let me explain.

  1. You can return function / functions
  2. You can return multiple useStates at once to make your code clean even throught it is used in only single file.
  3. You can split your logic and UI from to make the code even more organized.
  4. You can pass arguments into customHook and use them accordingly just like a function but with hooks power.

We will go into the logic section later where we can show the before & after effect of using custom hook so stay tuned.

Details

Hope you understand this soo far and I’m trying my best to make this topic as simple as possible.

Let’s move to the practical example.

Let’s say we have 2 components that needs user data and that user data will fetch from api and save on state,
If we normally do that we have to call that api in both components and save there data on seperate states and when something changes we have to change those 2 components as well and vise versa.

Okey now suppose we have UserProfile & UserSettings components.
First I’ll create those 2 components without custom hook and see what it looks like.

Now we have UserProfile component that looks like this.

import { useEffect, useState } from 'react'
import axios from 'axios'

function UserProfile() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      setIsLoading(true);
      try {
        const response = await axios.get(`/api/user`);
        setData(response.data);
      } catch (err) {
        setError(err);
      } finally {
        setIsLoading(false);
      }
    }
    fetchData();
  }, []);

  if (isLoading) return <p>Loading user data...</p>;
  if (error) return <p style={{ color: 'red' }}>Error loading user: {error.message}</p>;

  return (
    <div>
      <h3>{data.name}</h3>
      <p>Email: {data.email}</p>
      <p>Phone: {data.email}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

And we have UserSettings Component which looks like this.

import { useEffect, useState } from 'react'
import axios from 'axios'

function UserSettings() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      setIsLoading(true);
      try {
        const response = await axios.get(`/api/user`);
        setData(response.data);
      } catch (err) {
        setError(err);
      } finally {
        setIsLoading(false);
      }
    }
    fetchData();
  }, []);

  if (isLoading) return <p>Loading user data...</p>;
  if (error) return <p style={{ color: 'red' }}>Error loading user: {error.message}</p>;

  return (
    <div>
      <h3>Settings Page</h3>
      <p>Email: {data.email}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

As you see the codebase above 80% of the codebase is same only the return statement have some changes but if we don’t know custom hooks we usually do stuff like this and this is i call garbage code.

Now let’s create a custom and see how this makes our life easier.

const useUserData =()=>{
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      setIsLoading(true);
      setError(null);
      try {
        const response = await axios.get(`/api/user`);
        setData(response.data);
      } catch (err) {
        setError(err);
      } finally {
        setIsLoading(false);
      }
    }
    fetchData();
  }, []); 

  return {
    data,
    isLoading,
    error
  }
}
Enter fullscreen mode Exit fullscreen mode

Now that we have custom hook we can update the logic in both UserProfile and UserSettings and see how this optimized the workflow.

UserProfile.jsx

function UserProfile() {
  const { data, isLoading, error} = useUserData()

  if (isLoading) return <p>Loading user profile...</p>;
  if (error) return <p style={{ color: 'red' }}>Error loading user: {error.message}</p>;

  return (
    <div>
      <h3>{data.name}</h3>
      <p>Email: {data.email}</p>
      <p>Phone: {data.email}</p>
    </div>
  );
}    
Enter fullscreen mode Exit fullscreen mode

UserSettings.jsx

function UserSettings() {
  const { data, isLoading, error} = useUserData()

  if (isLoading) return <p>Loading user profile...</p>;
  if (error) return <p style={{ color: 'red' }}>Error loading user: {error.message}</p>;

  return (
    <div>
      <h3>Settings</h3>
      <p>Email: {data.email}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now that if we need to change anything in API we just have to update the custom hooks and all the components which are dependent on that hook will automatically reflect that change, So you don’t need to update each and every component from now on.

Details

tip: You can return jsx / tsx statement from hooks and it will be used in different component. Let’s say you have a {data.name} component and you think that component will later need some modifications so you can just return the component and then later use that in Components like that {badge} and send that using return statement .. return { badge:… }.. like this.

And there you have it.
Hope this article made your life a little easy/better.

If you want my assistence please reach me out on Github & Linkedin.

Top comments (0)