@VelinGeorgiev
@VesaJuvonen
Hi,
I have a question concerning dependency injection. I have a project setup with architecture similar to the IceCreamShop Samples. The Provider-Interfaces are being passed through the properties to the react component.
This works like a charm. From the outside I can provide specific implementations or within a test I can provide mocks.
However. When working with nested components this architecture ends up in bubbling the interfaces / dependencies from one property to the next property until it gets consumed by a nested child component.
Question: How would you implement a dependency injection in your example?
I have read many articles about react and di, but somehow I do not feel satisfied with all of them.
Using the reacts context as a place for sharing interface implementations feels wrong to me.
Higher Object Components are more suitable for compositing controls and I do not see a good strategy for resolving dependencies here.
The more I read, the more I am tempting to use third party modules like inversify.
What would you suggest?
I believe that in your example the most straight forward way would be having a possiblity to say:
export class IceCreamShop....
Constructor( // auto inject IIceCreamProvider here )...
Thanks for your opinion.
Regards
Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.
Hi @Link631, you did your homework, and you already kind of have the answer.
My personal opinions are the same as yours. Unfortunately, there isn't a solution out there that sounds nice. You will have to pick whatever you think is the least evil, but I will try to give you my detailed opinion below.
Less nesting when possible
Here is how I design my teams components. I try to use as little nesting as possible, usually on average, two levels of nesting. Occasionally, three levels of nesting where the third level of nesting does not have much logic than just to render data passed from the props and no state. This way, I have not got into a situation to think about more complex structures, but using such a technique might not always be possible.
Redux or React hooks
It seems that in the React world is more popular to use Redux or React hooks to transfer data from one place to another. I do not have experience with these patterns, but I think of it as something like the Observer pattern. If we use something like the redux or hooks, then your fourth or fifth level of nesting component can subscribe for an event and wait for that event to be fired from first-level nested service. The redux guys say that this Observer-Subscriber flow is debuggable. Still, I usually tend to avoid Observer patterns because I might end up with a system sending so many events to so many subscribers that it is hard to track. So, I think Redux or React hooks is something worth exploring for complex scenarios.
React context
I would not hesitate to try the React context since it is more straightforward over High-order components. The React guys had a thought on this and even stated it as sub-title of the context page - https://reactjs.org/docs/context.html
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
I fully agree with you! It is not ideal. I would try to keep the dependencies added to the React context to a minimum while meanwhile try also to reduce complex nestings with refactoring, where possible.
High-order components
They look too JavaScript. Not something a TypeScript or C# developer is used to see. I would avoid these since they might be hard to understand by my new junior teammates. Do not take this opinion for granted. That could be just my a different perception and lack of enough experience with the High-order components :).
Other DI JavaScript libraries
DI is quite popular among the C#, Java, and other backend languages. DI was working quite nice with Angular, but it was built-in to the framework, but React is not a complete framework, it is just the rendering part. My opinion is that DI library might seem confusing for an entry TypeScript/JavaScript dev. DI library might add a learning curve for the dev teammates, and trying to resolve dependencies at runtime might have a load and performance impact for your app. If I have to use one, I will do extensive research of which one has 1 - most stars in GitHub and is actively maintained, 2 - requires min learning path, 3 - is fast.
As I've said, I have not made your life easier, and thank you for your time if you've read all the text above. :)
I am adding @AustinBreslinDev to the discussion. He is a tech lead that knows many more concepts and patterns than me. If he sees this, he might also give you some direction.
Thank you very much for your answer))
I was expecting something like this while in the same time hoping to read an answer like: …. Yes…use another di framework😊
I have read About Higher Order Components a lot. Hooks are abstracting them in a more easy way. They are powerful but complex…. More Useful for saying: PageControl => Provide a function with :
AddPageHeader(type PageControl….)
So… in other words: I belive they are powerful for compositing…. But for simple di they are much too complex for my taste…
Thanks for your answer)))
Avoiding di and living with this situation until a certain depth in structure is something I can live with for the moment. 😊
Regards from Germany
Michael
You are welcome!
@Link631 thanks for the great question. We're so lucky to have @VelinGeorgiev share his wealth of knowledge on such topics!
I'll go ahead and mark this issue as closed, but feel free to add more to this discussion for the benefit of others.
Well... just for interest my experience with this architecture:
I followed the architecture of the IceCreamShop: Putting dependencies into properties.
I am following this strategy:
Each control consumes a manager, and a manager may consume a provider. The manager provides functionality for creating ViewModels, so it encapsulates the presentation logic like: is this button visible or not... So I can provide nice tests for presentation logic.
Controls are stupid binders.
Creation of dependencies is abstracted through an application Manager, which consumes a configuration provider and returns an Application Model containing all dependencies.
I managed to make the app manager replaceable by registering static instance. The first, who registers this instance wins. In my test I do register mock app manager before the app gets created. This creates one or two magic black boxes in my code, but they are on a very very top level at my application.tsx, so its not that bad. Other layers do get their providers and managers through properties or constructors.
Thus, I am able to test even the app by providing a mock configuration for all my layers.
I have also tried HOC architecture, but: Once it goes to testing, you end up needing to develope mock HOCs or you are kind of limited. Maybe I still did not get the way, how HOCs are testable.
I have develped complex controls with this architecture and until now I did not hit any limitations.
regards...
Thanks @Link631 for following up. It certainly looks like it would be a great opportunity for a sample web part, as I'm sure many folks would learn from your solution.
(Subtle hint 😎)
:))
Well it is basicly the architecture of the IceCreamShop but with one layer more... the presentation logic layer plus maybe a static instance, where kind of Configuration can be fetched from app or from test...
Ill think about an example ... maybe I can check something in.
Great, let us know if we can help in any way
Most helpful comment
:))
Well it is basicly the architecture of the IceCreamShop but with one layer more... the presentation logic layer plus maybe a static instance, where kind of Configuration can be fetched from app or from test...
Ill think about an example ... maybe I can check something in.