-
Notifications
You must be signed in to change notification settings - Fork 1
Description
As mentioned in the README, having many services offered by an app gets a bit intense. Because of how context works, it means we'd be looking at a lot of top-level nesting.
There is another possible option however - shared context.
Implementation Goal
The best APIs are designed for those who use them, not those who build them, so it's worth looking at how we might like to apply a single-provider service structure:
import { Services } from '@adamdickinson/react-service'
import { AuthService } from './services/auth'
import { NoticeService } from './services/notice'
import { ReportService } from './services/report'
const App = () => (
<Services services={[AuthService, NoticeService, ReportService]}>
...
</Services>
)import { useAuth } from './services/auth'
const SubComponent = () => {
const { user } = useAuth()
return <h1>{user?.name ?? 'Not logged in'}</h1>
}And if we wanted to, we should be able to expose services at various points in our app:
const App = () => (
<>
<Services auth={AuthService}>
<Services report={ReportService}>
...
</Services>
</Services>
<Services notice={NoticeService}>
...
</Services>
</>
)The smarter way to handle this would be as follows, but the above illustrates being able to expose many services with only a few providers well:
const App = () => (
<>
<AuthService>
<ReportService>
...
</ReportService>
</AuthService>
<NoticeService>
...
</NoticeService>
</>
)How do we accomplish this?
A single context seems to be the way...
const ServiceContext = React.createContext()
interface ServicesProps {
services: Service[]
}
const Services = ({ children, ...services }) => {
const existingApis = useContext(ServiceContext)
const apis = {
// Carry forward higher-level services
...existingApis
// Add newly defined services
...Object.keys(services).reduce((newApis, name) => {
apis[name] = services[name].useApi()
}, newApis)
}
return (
<ServiceContext.Provider value={apis}>
{children}
</ServiceContext.Provider>
)
}Benefits
The simple benefit is that we can now throw in a heap of services without a nesting nightmare, but we could do that without many architectural changes, so why does the above proposal attempt to wrap everything in a single context? Because it allows us to get services talking to each other. Let's say you have a Data service that uses Auth info, and an Auth service that will make use of unauthorised processes in the Data service - this structure will allow us to do this.
More thoughts on the way on this one.