Skip to main content

Scopes in React

This guide covers how to use request scopes in React applications with ScopeProvider.

Overview​

ScopeProvider creates isolated request scopes for dependency injection. Services with scope: 'Request' will be instantiated once per scope and shared among all components within that provider.

Basic Usage​

import { ScopeProvider } from '@navios/di-react'

function Table({ rows }) {
return (
<table>
{rows.map((row) => (
<ScopeProvider key={row.id} scopeId={row.id}>
<TableRow />
</ScopeProvider>
))}
</table>
)
}

Table Rows Example​

Each table row gets its own isolated service instance:

import { Injectable, InjectableScope } from '@navios/di'
import { ScopeProvider, useService } from '@navios/di-react'

@Injectable({ scope: InjectableScope.Request })
class RowService {
private data: any

setData(data: any) {
this.data = data
}

getData() {
return this.data
}
}

function TableRow({ row }) {
const { data: rowService } = useService(RowService)

useEffect(() => {
rowService?.setData(row)
}, [rowService, row])

return <tr>{/* Row content */}</tr>
}

function Table({ rows }) {
return (
<table>
{rows.map((row) => (
<ScopeProvider key={row.id} scopeId={row.id}>
<TableRow row={row} />
</ScopeProvider>
))}
</table>
)
}

Each modal gets its own isolated service instance:

function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null

return (
<ScopeProvider scopeId={`modal-${Date.now()}`}>
<ModalDialog onClose={onClose}>{children}</ModalDialog>
</ScopeProvider>
)
}

Accessing Scope Information​

useScope​

Get the current scope ID:

import { useScope } from '@navios/di-react'

function MyComponent() {
const scopeId = useScope()

if (!scopeId) {
return <div>Not in a scope</div>
}

return <div>Current scope: {scopeId}</div>
}

useScopeOrThrow​

Get the current scope ID, throwing an error if not inside a ScopeProvider:

import { useScopeOrThrow } from '@navios/di-react'

function MyComponent() {
const scopeId = useScopeOrThrow() // Throws if not in ScopeProvider

return <div>Current scope: {scopeId}</div>
}

useScopeMetadata​

Get metadata from the current scope:

import { useScopeMetadata } from '@navios/di-react'

function ChildComponent() {
const userId = useScopeMetadata<string>('userId')
const theme = useScopeMetadata<'light' | 'dark'>('theme')

return (
<div>
User: {userId}, Theme: {theme}
</div>
)
}

// In parent component:
<ScopeProvider metadata={{ userId: '123', theme: 'dark' }}>
<ChildComponent />
</ScopeProvider>

Best Practices​

1. Use ScopeProvider for Isolation​

// ✅ Good: Isolated scopes for each row
{rows.map((row) => (
<ScopeProvider key={row.id} scopeId={row.id}>
<TableRow />
</ScopeProvider>
))}

2. Provide Meaningful Scope IDs​

// ✅ Good: Descriptive scope IDs
<ScopeProvider scopeId={`user-${userId}`}>

// ❌ Avoid: Generic scope IDs
<ScopeProvider scopeId="scope">

3. Use Metadata for Context​

// ✅ Good: Provide context via metadata
<ScopeProvider
scopeId={`order-${orderId}`}
metadata={{ orderId, userId, timestamp: Date.now() }}
>
<OrderDetails />
</ScopeProvider>

Next Steps​