Apply the Dependency Inversion Principle in React
Tags: javascript, react, programming, tutorial
Published: 2023-07-22 09:20:00

**_To read more articles like this, [visit my blog](https://www.mdfaisal.com/blog)_**



The *dependency inversion* principle is one of the famous SOLID principles. Also, it is one of the most important ones.

Today, we will see how to solve a very common mistake that novice React developers make using this principle.

I will try to keep it very simple. Let’s get started!

## What Does This Principle Tell Us?

In terms of object-oriented programming, the main idea behind this principle is to always have a high-level code interface with abstraction rather than an implementation detail.

Hold on! I know what you are thinking: “I am a simple frontend developer. Why are you bothering me with these complex terms?”

Let me state it simply for you. For a React application, this principle means:
>  “No component or function should care about how a particular thing is done.”

Still not clear? OK, let’s get our hands dirty with some code!

## A Practical Example

Let’s take a very common use case. We are going to make an API call from our component to get some data from a remote source. An implementation can look like this:

```js
import React from "react";

const REMOTE_URL = 'https://jsonplaceholder.typicode.com/users'

export const Users = () => {
  
    const [users , setUsers] = useState([])

    useEffect(() => {
      
      fetch(URL)
        .then(response => response.json())
        .then(json => setUsers(json))
        
    },[])

    return <>
        <div> Users List</div>
        {filteredUsers.map(user => <div>{user.name}</div>)}
    </>
}
```

Look at this component. It depends on some remote data that is fetched right inside the component.

Our `Users` component’s main responsibility is to render the data. It should not care about how data is fetched or where the data comes from.

This component knows too much — and that’s a problem.

## Why?

Well, let’s say you have ten other components and all of them fetch their own data.

Now your manager comes along and tells you to use `axios` instead of `fetch`

You are in trouble! Now you have to go into each file and refactor the logic to use `axios`.

But life is not so simple! After a few days, your manager comes again and tells you to implement caching.

You have to do the same thing once again.

Thus, it increases the chance of introducing a bug in your software. Also, the code becomes unmaintainable and valuable time is wasted.

## So What Should We Do Then?

Let’s introduce a data-fetching Hook and abstract away our logic outside our component because that’s exactly what this principle tells us. To depend on abstraction, remember?

```js
import {useState} from "react";

export const useFetch = (URL) => {

    const [data , setData] = useState([])

    useEffect(() => {
      
        fetch(URL)
            .then(response => response.json())
            .then(json => setData(json))
            
    },[])

    return data;

}
```

Now use this Hook inside our `Users` component:

```js
import React from "react";
import useFetch from './useFetch'

const REMOTE_URL = 'https://jsonplaceholder.typicode.com/users'

export const Users = () => {
  
    const users = useFetch(REMOTE_URL)

    return <>
        <div> Users List</div>
        {filteredUsers.map(user => <div>{user.name}</div>)}
    </>
}
```

Notice a great thing about this solution: Your `useFetch` Hook doesn’t care about who is calling it. It just takes a `URL` as an input and returns the data.

Now all other components can take advantage of the Hook that we just wrote. And our `Users` component no longer depends on the concrete details on how the data is coming back or which library is being used!

## More Advanced Usage

Now let’s satisfy your manager with basic caching functionality:

```js
import {useState} from "react";

export const useFetch = (URL) => {

    const [data , setData] = useState([])

    useEffect(() => {
      
      const cachedData = localstorage.getItem(URL)
      
      if(cachedData) {
        setData(JSON.parse(cachedData))
      }
      else{
        fetch(URL)
        .then(response => response.json())
        .then(json => setData(json))
      }
            
    },[URL])
    
    useEffect(() => {
      localstorage.setItem(URL , JSON.stringify(data))
    },[data])

    return users;

}
```

You have to change the code in only one place now. That’s great! Let’s say you need to show API errors as a toast. Can you do that now? If so, then you got my point.

## How To Detect It

* In most cases, if you are violating the single-responsibility principle, then you might also be violating the dependency inversion principle.

* For any component, look into the import section at the top. If you are importing some library that’s not responsible for displaying something (e.g. a toast or modal), then you might be violating the principle.

## Previous Articles in this Series

 1. [Single Responsibility Principle](https://betterprogramming.pub/how-to-apply-solid-principles-to-clean-your-code-in-react-cdfd5e0a9cea)

 2. [Open Closed Principle](https://betterprogramming.pub/applying-the-open-closed-principle-to-write-clean-react-components-4e4514963e40)

 3. [Liskov Substitution Principle](https://betterprogramming.pub/applying-the-liskov-substitution-principle-in-react-3a0614a42a08)

 4. [Interface Segregation Principle](https://betterprogramming.pub/how-to-apply-interface-segregation-principle-in-reactjs-fadf77113c5d)

That’s all for today. I hope you enjoyed this article as well as this series.

**Have something to say? Get in touch with me via [LinkedIn](https://www.linkedin.com/in/56faisal/) or [Personal Website](https://www.mdfaisal.com/)**