ReactJS HOC — how to inject dependencies to React component in AngularJS way

Radek Anuszewski
Frontend Weekly
Published in
3 min readMay 12, 2018

When you have Angular background and you switch to React, you may miss the way how it handles dependencies. With Higher Order Component (HOC) pattern it can be easily imitated in React.

I found Dependency Injection as one of the most useful concept in IT. Photo credits: Pixelbay.

Note — code for my example is available on Github: React Weather — Repo used to learn React, Redux and Workers.

AngularJS

Dependency injection in one of the most popular framework in the world.

AngularJS has a guide about dependency injection. Framework uses constructor injection, and looks like this:

angular
.module('app')
.controller('UserController', function (UserService) {
var $ctrl = this;
this.$onInit = function () {
UserService
.getAll()
.then(function (users){
$ctrl.users = users;
});
});

UserService factory implementation:

angular.module(‘app’)
.factory(‘UserService’, function ($http) {
return {
getAll: getAll,
};

function getAll () {
return $http.get(‘api/users’);
}
});

Factory implementations means AngularJS evaluates function and injects object with getAll property. UserService can also be created as service:

angular.module('app')
.service('UserService', function ($http) {
this.getAll = function () {
return $http.get('api/users');
}
});

The main difference is that framerowk instantiates function with new operator, so visible properties need to be bound to this.
Important information for Java developers is that Spring allows constructor dependency injection:

@RestController
@RequestMapping(“api/users”)
public final class UserController {
private final UserService service;@Inject
public UserController(final UserService service) {
this.service = service;
}
@GetMapping
public List<UserDTO> getAll() {
return service.getAll();
}
}

Which for me is huge advantage — it’s common case that backend developers move to front/full stack and they can found things which they are familiar with.

React

No native dependency injection

React does not have dependency injection concept. Maybe there is No Need for Dependency Injection in React Components. It depends — when you are “AngularJS guy” for many years, maybe you won’t want to learn another concepts especially that new concepts and frameworks in JS appear every second. Dependency injection is forever.

Living without dependency injection at all

When you decide to forget about DI known from AngularJS world, and to don’t use Max Heiber’s advices, but you still want to keep logic outside view — your code looks pretty much like this:

class Forecast extends Component {
constructor (props) {
super(props);

this.apiService = new ApiService({
key: props.apiKey,
});
}
}

Which ties ApiService to Forecast component and maybe needs some additional effort for testing purposes. But today, I figured out a solution.

Higher Order Components (HOC) as solution for dependency injection

Higher Order Components are pretty well explained in post Understanding React Higher-Order Components by Example by Trey Huffine.
Basically, they are used to share things across application, to reduce code duplication and to group these things in one place to make changes easier.
So, HOCs are great for imitating dependency injection!

Injecting apiService with Higher Order Components

First, we need to create a HOC named withApiService, which is function:

function withApiService (WrappedComponent) {
class HOC extends React.Component {
render () {
const key = this.props.apiKey;
const apiService = new ApiService({key});

return (
<WrappedComponent
{...this.props}
apiService={apiService}
/>
);
}
}
return HOC;
}

It takes component to decorate and adds property to inject.
It’s very important to note that Forecast component now takes apiService from properties:

class Forecast extends Component {
constructor (props) {
super(props);

this.apiService = props.apiService;
}

But how to use decorated component? We need to replace component usage in render function with new version.
Before, without DI:

render() {
const {apiKey, cityId} = this.state;

return (
<Forecast
cityId={cityId}
apiKey={apiKey}
/>
);
}

After, with DI:

render() {
const {apiKey, cityId} = this.state;
const WrappedForecast = withApiService(Forecast);

return (
<WrappedForecast
cityId={cityId}
apiKey={apiKey}
/>
);
}

Previously rendered component now is replaced with decorated version.

Conclusion

I found Higher Order Components very useful. Imitating DI is only one of them, and I am sure that we will read more and more about them. I remind that code from this post exists in Github: React Weather — Repo used to learn React, Redux and Workers.

--

--

Radek Anuszewski
Frontend Weekly

Software developer, frontend developer in AltConnect.pl, mostly playing with ReactJS, AngularJS and, recently, BackboneJS / MarionetteJS.