DEV Community

Dependency Injection /Services pattern for React (inspired by Angular)

Daniel Sollie Hansen on July 09, 2021

Having worked in an Angular-development team for several years, it was exciting for me to learn React and it's more lightweight approach to web-dev...
Collapse
 
larsejaas profile image
Lars Ejaas

I am trying to wrap my head around this idea and understand if/why this is a great idea. I follow you as far as using a hook for the fetch logic. I always prefer moving the logic for something like this into a custom hook. However, what is the added benefit of using context when you can access the service from the hook? To cache data??? 🤔

Collapse
 
dansolhan profile image
Daniel Sollie Hansen

Thank you for the comment! :)

The way I see it, the benefit comes when you're testing. When you need to test a component that relies on the service, you include a context provider when you render for the test. You can then set the value for that provider to be a mock implementation of that service.

Does that make sense?

Collapse
 
larsejaas profile image
Lars Ejaas

Ahh, yeah! That makes sense! I still have a lot to learn when it comes to testing, so I really wasn't thinking about that.

Thread Thread
 
dansolhan profile image
Daniel Sollie Hansen

Glad that clears it up! :)

I know Jest comes with a set of functions to be able to mock components, and I'm not veery used to using them. I find this particular solution makes it easier to mock components on the fly, while also enabling abstracting away concerns. It's entirely possible that there are more elegant built-in ways that I just haven't explored yet :)

Thread Thread
 
dansolhan profile image
Daniel Sollie Hansen

If you think it might be useful, I can see about making a tutorial for how to think when writing tests in this manner!

Thread Thread
 
larsejaas profile image
Lars Ejaas

Well, I do not see your solution as a bad implementation at all, I just feel you sometimes tend to get a bit of "context-provider-hell" working with things like styled components and Apollo-client etc. I just wich this could be done in a cleaner way in React.

Thread Thread
 
dansolhan profile image
Daniel Sollie Hansen

I'll admit that I just very shortly touched into StyledComponents... I did not like it at all :P.

Jack seems to have built a possibly viable solution for a full-fledged DI-system. It's probably more refined than mine!

Thread Thread
 
larsejaas profile image
Lars Ejaas

LoL 😂 Styled components is a bit of a love/hate relationship I guess. But it can be really powerful when you want to do things with styling that are a bit out of the ordinary. I used it yestoday to create a cool "unwrap" effect animating some nested nav-menus where I the height of elements that would change depending on what is placed in the menu: Stuff you just can't do with "traditional" ways of styling. I bookmarked Jacks Solution - looks like something that might come in handy!

Collapse
 
jackmellis profile image
Jack

I felt the exact same way when i moved from angular to react a few years ago, which is why I wrote and constantly plug react-jpex for DI:
dev.to/jackmellis/dependency-injec...

Collapse
 
rafaelplantard profile image
Rafael da Silva Ferreira • Edited

Hi, I really liked your approach, but I do not understood how I could inject a value in a unit test for my service.

// declaration
export default class FeatureToggleServiceImpl implements IFeatureToggleService {
  private native = useNativeCommunicationService(); // how could I initialize it when running unit tests.

  constructor() {
    /// ...
  }


// test

let service: IFeatureToggleService;

beforeEach(() => {
  // how I could inject the value for useNativeCommunicationService?
  service = new FeatureToggleServiceImpl();
})
Enter fullscreen mode Exit fullscreen mode
Collapse
 
fasidongit profile image
Kader Mohideen Fasid • Edited

Great article!. What about tree-shakability ? I assume Angular services are tree-shakable despite being singleton.

IIUC, If we registered all our services in the GlobalServices, then it would make it available across the app but we loss the benefit of tree-shakability, right ? meaning these services are there before they are needed (i wonder how that would affect initial page load on a very big react app with lot of services registered). I understand we could choose not to provide them in the GlobalServices rather provide only where it's needed. then, in that case due to the nature of context. we will end up having to provide my services in multiple places which is bit of a extra step and cumbersome IMO. Or Did I misunderstood something ?

Collapse
 
petroskoulianos profile image
Petros Koulianos

I like your approach with the DI and the generic way to get new services.

DI is something that is missing from React apps

Collapse
 
dansolhan profile image
Daniel Sollie Hansen

Thanks a bunch! Glad it was helpful. And I agree. Some kind of DI-container would have been really helpful straight from the box

Collapse
 
gobieljonathan profile image
Jonathan Gobiel

Good idea, but is it possible to make hell provider if have some much context to wrap

Collapse
 
dansolhan profile image
Daniel Sollie Hansen

Hi! Thanks for your comment. I'm afraid I'm not sure I understand completely what you mean? :)

Collapse
 
gobieljonathan profile image
Jonathan Gobiel

yeah i mean, if so much context have been made, it could make hell provider, can you tell, how to void ?

Thread Thread
 
dansolhan profile image
Daniel Sollie Hansen

If I get you correctly, you're worried that you'll clog the template with services? My solution to this was to put all Services inside a GlobalServices that is then wrapped around the App. Does that answer your question?

Thread Thread
 
gobieljonathan profile image
Jonathan Gobiel

yeah it's good solution, but there's any approach method to make Dependecy Injection without using context?

Thread Thread
 
dansolhan profile image
Daniel Sollie Hansen

I'd assume so! If you check my comments, you can see that Jack has made a solution that seems very viable!

Collapse
 
khorne07 profile image
Khorne07 • Edited

I've been learning TypeScript for a few weeks now and still figuring out how to make things in the best way using it. This post was a really great thing to see. Thanks 👍

Collapse
 
dansolhan profile image
Daniel Sollie Hansen • Edited

Oh hey! Very glad that you found it helpful :) Thanks a bunch