1

I'm trying to use InversifyJS in a react native application that uses a functional approach to components. I have everything configured and working as it should, however, the only way in which I can achieve dependency injection is through using the service locator pattern (something I want to avoid):

const Settings = (props: ISettingsProps) => {
 const dispatch = useDispatch();
 const navigationService = useInjection<INavigationService>(TYPES.NavigationService);
 return (
 <AuthenticatedView {...{ ...props, style: {justifyContent: 'flex-start', marginTop: '70%', alignItems:'center'}}}>
 <Text>Settings!</Text>
 <Button onPress={() => navigationService.navigate(props, "Trade", dispatch)} title="Trade" />
 </AuthenticatedView>
 )
}
export default Settings;

The code above uses a navigation service that is located using the aforementioned service locator.

What I would like to do, is inject the service into the component using props however, I can't seem to work out how to do this. I have consulted several tutorials, including this one:

https://synergycodes.com/blog/dependency-injection-in-react-using-inversifyjs/

There seems to be a way if I use @lazyInject, perhaps - but, that way of doing DI only appears to be supported in class based components (I would like to stick with functional, since react themselves recommend this particular paradigm).

I tried this:

@lazyInject(TYPES.NavigationService) let navigationService: INavigationService;

But I get the following error:

Decorators are not valid here

However, that seems like a step in the right direction (if I can get it to work).

asked Mar 7, 2024 at 7:01

1 Answer 1

0

The answer to this appears to be that custom dependency injection / IOC should be avoided. At least, this is the case when hooks are being used. The approach that I have taken, is to use the createContext hook in order to register and consume dependencies.

First I register the dependencies in a custom AppContextWrapper component. In this case, I have two dependencies: authService and navigationService

interface IAppContext {
 authService: IAuthService;
 navigationService: INavigationService;
}
const contextDependencies = {
 authService: new AuthService(),
 navigationService: new NavigationService()
}
export const AppContext = createContext<IAppContext | null>(null);
export default function AppContextWrapper(props: IApplicationProps) {
 return (
 <AppContext.Provider value={contextDependencies}>
 {props.children}
 </AppContext.Provider>
 );
}

Then wrap the main App.tsx with the wrapper:

export default function App() {
 return (
 <AppContextWrapper>
 ...
 </AppContextWrapper>
 )
}

I can then call the context and get the type that is required by using useContext in the child components. Here I'm using the navigationService in my Settings screen:

const Settings = (props: ISettingsProps) => {
 const dispatch = useDispatch();
 const navigationService = useContext(AppContext)?.navigationService;
 return (
 <AuthenticatedView {...{ ...props, style: {justifyContent: 'flex-start', marginTop: '70%', alignItems:'center'}}}>
 <Text>Settings!</Text>
 <Button onPress={() => navigationService?.navigate(props, "Trade", dispatch)} title="Trade" />
 </AuthenticatedView>
 )
}
export default Settings;

This is closely related to a service locator pattern, however, there doesn't seem to be a way around that. This appears to be cleanest way of achieving DI with modern react.

answered Mar 12, 2024 at 20:40
Sign up to request clarification or add additional context in comments.

2 Comments

In case this is still relevant - I've developed a DI library for React and React Native. It lets you inject dependencies into components and hooks. You might find it interesting github.com/wix-incubator/obsidian
Very cool...I'll try this out.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.