Dependency Injection in React — Part 1
React has dependency injection
Over the past few months, I have read many articles about Dependency Injection specifically in React. And often you can stumble upon the arguments why DI is not needed in React. In fact, React has built-in dependency injection. You inject your dependencies via properties.
therefore, we can inject some scalar data and functions(`bindActionCreators({ doTheWorkOnClick})`) that will be responsible for the complex logic that you want to keep outside the component.
But the thing is it’s a simple scenario. What if I need to pass `browserHistory` object.
How would you do this?
It’s a really simple case but in order to use “built-in” React DI you will need to pass ALL the properties required in child components from App to the very very last. In practice, it certainly does not work.
And at that moment a React Context appears
That, in fact, is a container for a single dependency. And when you wrap your components with withRouter, withCookie, etc decorators, in fact, you will create a HOC component that wraps your target component. It will read a required property from context and inject it into your component.
Let’s imagine how would we build withLogger decorator
Why I don’t like decorators?
One more note regarding the unobvious effect when we use with decorators. Ok, we have withRouter decorator from react-router package, that does this DI magic for us. Let’s use it in our HomePage component.
You cannot mount the component because withRouter version of your component now expect that it’s a child component for <BrowserRouter> — context consumer component.
A decorator is a nice tool, they can hide quite complex logic while your code is still short and clear. But your component will NOT.
when you wrap your components with multiple decorators at the end you’ll have a beast. And in order to test it, you will need to build the whole environment.
The funny thing that somebody still will call such tests as unit tests. It’s not true — it’s integration tests since you integrate other components to test one unit. They are much slower and harder to maintain.
Give me a better option
In real life, in order to inject a dependency to the component, I have to write decorators for each dependency I have— withLogger, withCurrentUser, withStorage, etc.
So my question is why I cannot have a single container/context that would keep all my dependencies for the app?
Learn why and how did I build my own dependency injection container in part 2.