use-selektor
v2.1.0
Published
Context selector utilities for React contexts
Maintainers
Readme
useSelektor
useSelektor is a React context-selector utility for reading only the slice of state a component needs. It uses a subscription model so consumer components update when their selected value changes, not when unrelated context keys change.
Features
- Fully typesafe selector API
- Prevents selector consumers from rerendering on unrelated state updates
- Custom equality support for derived selector output
- Optional default context value for safe reads without a matching provider
- Named after He-Man's primary antagonist
Usage
- Create a selector-aware context with
createSelektorContext. - Render its
Providerwith the current state value. - Read slices with
YourContext.useSelektor(selector, isEqual?).
API
createSelektorContext<State>(): SelektorContext<State>
createSelektorContext<State>(defaultValue: State): SelektorContext<State>- Without
defaultValue, callinguseSelektorwithout a matching provider throws. - With
defaultValue, callinguseSelektorwithout a matching provider selects from the default state.
Example
import { createSelektorContext } from 'use-selektor'
import { useMemo, useState } from 'react'
type Item = {
id: string
label: string
value: number
}
type AppState = {
items: Record<string, Item>
selectedId: string
theme: 'light' | 'dark'
}
const AppContext = createSelektorContext<AppState>()
function ItemTitle() {
const title = AppContext.useSelektor(state => state.items[state.selectedId].label)
return <h2>{title}</h2>
}
function ThemeBadge() {
const theme = AppContext.useSelektor(state => state.theme)
return <span>{theme}</span>
}
export function App() {
const [state, setState] = useState<AppState>({
items: {
a: { id: 'a', label: 'Alpha', value: 1 },
b: { id: 'b', label: 'Beta', value: 2 },
},
selectedId: 'a',
theme: 'light',
})
const value = useMemo(() => state, [state])
return (
<AppContext.Provider value={value}>
<ItemTitle />
<ThemeBadge />
<button
onClick={() => {
setState(prev => ({ ...prev, theme: prev.theme === 'light' ? 'dark' : 'light' }))
}}
>
Toggle Theme
</button>
</AppContext.Provider>
)
}Custom Equality
Use isEqual when your selector returns derived objects:
const userPreview = UserContext.useSelektor(
state => ({ id: state.user.id, name: state.user.name }),
(a, b) => a.id === b.id && a.name === b.name
)Default Value Fallback
Pass an initial default state to avoid runtime errors in places where a provider may be missing:
type SessionState = {
user: { id: string; name: string } | null
locale: string
}
const SessionContext = createSelektorContext<SessionState>({
user: null,
locale: 'en',
})
function Header() {
const locale = SessionContext.useSelektor(state => state.locale)
return <span>{locale}</span>
}In this setup, Header reads from the default value when rendered outside SessionContext.Provider.
Migration from v1
useSelektor(selector, reactContext) has been removed in v2.
Legacy:
const result = useSelektor(selector, SomeReactContext)V2:
const SomeContext = createSelektorContext<State>()
function Child() {
const result = SomeContext.useSelektor(selector)
return <>{result}</>
}Replace plain React context + standalone hook usage with the factory-generated provider and hook pair.
License
use-selektor is licensed under the ISC License. See the LICENSE file for more details.
Additional Resources
- GitHub Repository – Source code and issue tracking.
Thank you for choosing use-selektor. May your schemas be consistent and your renders infrequent
