Dependency Inversion or Dependency Injection in React: That is the Question

01.06.23 by Marzieh Moghtaderi

Dependency Inversion or Dependency Injection in React: That is the Question

Delivery Hero Logo

4 min read

Although inversion of control, dependency injection, and dependency inversion concepts share some common ground, differentiating between them can be challenging. In this article, we will delve into each of these concepts and explore practical examples of how they are used in React applications.

As developers, we work with a variety of best practices and design patterns in our day-to-day work. Whether we are conscious of them or simply follow the code handed to us, knowing these practices can provide us with a better understanding of why we follow certain repetitive methods, and how we can create better architecture projects in the long term.

In modern software development, there are three distinct concepts that are similar yet different: inversion of control, dependency injection, and dependency inversion. 

Inversion of Control

Inversion of Control (IoC) is a design pattern in which the control flow of a computer program is handled by a portion of the program other than the main one.

One of the implementations of IoC is the dependency injection design pattern, which is used when a function needs to use a service. With dependency injection, the function doesn’t need to know the details of how the service works. Instead, the external code for the service should be provided (injected) as a dependency.

We can see a similar approach with callbacks in JavaScript. When we pass a callback handler to a function, we delegate the responsibility of invoking the handler at the right time and with the right values to that function. This design pattern increases modularity, resulting in more loosely coupled systems that promote the separation of concerns and simplicity.

However, no good comes without a cost. Since we are giving control of the program to another function, we need to think twice before trusting third-party libraries or services.

Dependency Injection in React

In React, our building blocks are components. If we apply the concept of dependency injection to React, it means that when a component needs to use a function or data (like a service), that service requires an executor to take over control when the component calls upon it. We can see this architecture in various places of our applications.

A simple example would be when we pass data or a function to a child component from a parent component, or when we use custom hooks to reuse some modifications on data that will be used across multiple components.

But let’s look at it at the system level – when we need information in a high-level component while having some low-level components that need the data, and might need to modify it. It’s not a good idea to manually pass the app’s language data or theming information through each element on the page.

We can use the Context API to share this type of data between components without the need to pass it through props. By doing so, we can avoid prop drilling and ensure that the data is available to every element that needs it. By minimizing the frequency of passing data through multiple components, we can create a more organized and efficient codebase. This will make it easier to maintain and update our application over time.

As you can see in the example below, we create the context and the provider. It can be used by wrapping over a top-level component and consuming the application’s language via the useContext hook in any children of it.

Dependency Inversion Principle

The “D” in the SOLID design principles represents the Dependency Inversion Principle. This principle emphasizes the traditional dependency relationships between high-level and low-level modules, with both depending on an abstraction that serves as the connection bridge between them.

This principle helps to reduce the interdependence between modules and makes it easier to modify, replace, or test individual components without affecting the entire system.

As a result, the dependency inversion principle promotes the same values as dependency injection in the big picture, but it achieves them in a different way.

Dependency Inversion in React

When building a React application, we often use low-level components like buttons. However, buttons can have various types, styles, states, and variants, making them more complex than they initially appear.

To use a button in a high-level component, such as a main page or form, we need to import an abstraction of the button component that contains all the complexity within its sub-branch and only exposes a final API in the abstraction.

This approach allows us to modify button styles, states, and behaviour without changing anything in the high-level components and without affecting the overall functionality of the application, as long as the exposed API remains the same.

It is especially useful when using third-party design systems, as we can adjust and react to the new updates and changes of that design system or even change the whole design system with another one, only by implementing modifications in our button abstraction (low-level components) while leaving the high-level components untouched.

The example UML illustrates that as long as the props and default props of the “MyProjectButton” do not change, high-level components do not need to know how the button is created, styled, and maintained.

When we implement the dependency inversion principle, we can change the style of the primary variant in our button component only within the “MyProjectButton“, and all usages in the high-level elements will be affected accordingly. Without dependency inversion, we’d have to implement the changes in two places (for now), and repeating code makes it difficult to maintain consistency as the project grows and time passes.


If you like what you’ve read and you’re someone who wants to work on open, interesting projects in a caring environment, check out our full list of open roles here – from Backend to Frontend and everything in between. We’d love to have you on board for an amazing journey ahead.

Dependency Inversion or Dependency Injection in React: That is the Question
Marzieh Moghtaderi
Staff Software Engineer
Delivery Hero’s New Grad Program: Empowering Future Talent and Embracing Diversity

Next

Engineering

Delivery Hero’s New Grad Program: Empowering Future Talent and Embracing Diversity

Delivery Hero Logo
4 min read