Gathering detailed insights and metrics for jotai-scope
Gathering detailed insights and metrics for jotai-scope
Gathering detailed insights and metrics for jotai-scope
Gathering detailed insights and metrics for jotai-scope
@singee/jotai-scope
👻🔭
scope-state
Scope State is the simplest global state system for React that you've ever used — no boilerplate, no spreading, no mental overhead.
jotai-capsule
An alternative approach to scoping Jotai atoms. A capsule is used as a namespace for atoms. By wrapping a component with a capsule provider, a new scope is created.
jotai-sync-scope
Library for syncing Jotai atoms
npm install jotai-scope
Typescript
Module System
Min. Node Version
Node Version
NPM Version
95.9
Supply Chain
95.2
Quality
92.9
Maintenance
100
Vulnerability
100
License
TypeScript (100%)
Total Downloads
1,794,374
Last Day
3,627
Last Week
67,597
Last Month
251,100
Last Year
1,523,815
MIT License
73 Stars
76 Commits
5 Forks
3 Watchers
4 Branches
9 Contributors
Updated on Aug 02, 2025
Latest Version
0.9.3
Package Id
jotai-scope@0.9.3
Unpacked Size
95.08 kB
Size
27.92 kB
File Count
21
NPM Version
10.8.2
Node Version
20.19.3
Published on
Jul 17, 2025
Cumulative downloads
Total Downloads
Last Day
-2.9%
3,627
Compared to previous day
Last Week
1.8%
67,597
Compared to previous week
Last Month
5.7%
251,100
Compared to previous month
Last Year
464.1%
1,523,815
Compared to previous year
22
👻🔭 Isolate Jotai atoms with scope
npm install jotai-scope
While Jotai's Provider allows to scope Jotai's store under a subtree, we can't use the store above the tree within the subtree.
A workaround is to use store
option in useAtom and other hooks.
Instead of specifying the store
option, <ScopeProvider>
lets you reuse the same atoms in different parts of the React tree without sharing state while still being able to read other atoms from the parent store.
atoms
or atomFamilies
are explicitly scoped.1import { Provider, atom, useAtom, useAtomValue } from 'jotai' 2import { ScopeProvider } from 'jotai-scope'
1 · Isolating a counter
1const countAtom = atom(0) 2const doubledAtom = atom((get) => get(countAtom) * 2) 3 4function Counter() { 5 const [count, setCount] = useAtom(countAtom) 6 const doubled = useAtomValue(doubledAtom) 7 return ( 8 <> 9 <button onClick={() => setCount((c) => c + 1)}>+1</button> 10 <span>{count} → {doubled}</span> 11 </> 12 ) 13} 14 15export default function App() { 16 return ( 17 <Provider> 18 <Counter /> {/* doubledAtom uses the parent store */} 19 <ScopeProvider atoms={[doubledAtom]}> 20 <Counter /> {/* doubledAtom is scoped */} 21 </ScopeProvider> 22 </Provider> 23 ) 24}
The second counter owns a private doubledAtom
and a private countAtom
because doubledAtom
is scoped.
2 · Nested scopes
1<ScopeProvider atoms={[countAtom]} name="S1"> 2 <Counter /> {/* countAtom is read from S1 */} 3 <ScopeProvider atoms={[nameAtom]} name="S2"> 4 <Counter /> {/* countAtom is read from S1 & nameAtom is read from S2 */} 5 </ScopeProvider> 6</ScopeProvider>
countAtom
.nameAtom
, then looks up the tree and finds countAtom
in S1.3 · Providing default values
1<ScopeProvider atoms={[[countAtom, 42]]}> 2 <Counter /> {/* starts at 42 inside this scope */} 3</ScopeProvider>
Mix tuples and plain atoms as needed: atoms={[[countAtom, 1], anotherAtom]}
.
4 · Scoping an atomFamily
1import { atom, atomFamily, useAtom } from 'jotai' 2import { ScopeProvider } from 'jotai-scope' 3 4const itemFamily = atomFamily((id: number) => atom(id)) 5 6<Component /> {/* Unscoped items */} 7<ScopeProvider atomFamilies={[itemFamily]}> 8 <Component /> {/* Isolated items */} 9</ScopeProvider> 10
Inside the <ScopeProvider>
every itemFamily(id)
call resolves to a scoped copy, so items rendered inside the provider are independent from the global ones and from any sibling scopes.
A helpful syntax for describing nested scopes
a, b, c(a + b), d(a + c)
S1[a]: a1, b0, c0(a1 + b0), d0(a1 + c0(a1 + b0))
S2[c, d]: a1, b0, c2(a2 + b2), d2(a2 + c2(a2 + b2))
Above:
1interface ScopeProviderProps { 2 atoms?: (Atom<any> | [WritableAtom<any, any[], any>, any])[] 3 atomFamilies?: AtomFamily<any, any>[] 4 children: React.ReactNode 5 name?: string 6} | { 7 scope: ScopedStore 8 children: React.ReactNode 9}
createScope
is a low-level API that allows you to create a scoped store
from a parent store. It is useful when you want to create a scope
outside of React.
1import { createScope, ScopeProvider } from 'jotai-scope' 2 3const parentStore = createStore() 4const scopedStore = createScope({ 5 parentStore, 6 atomSet: new Set([atomA, atomB]), 7 atomFamilySet: new Set([atomFamilyA, atomFamilyB]), 8}) 9 10function Component() { 11 return ( 12 <ScopeProvider scope={scopedStore}> 13 <YourComponent /> 14 </ScopeProvider> 15 ) 16}
You can create a scope from another scope.
1const parentStore = createStore()
2const scope1 = createScope({
3 parentStore,
4 atomSet: new Set([atomA, atomB]),
5 atomFamilySet: new Set([atomFamilyA, atomFamilyB]),
6 scopeName: 'level1',
7})
8const scope2 = createScope({
9 parentStore: scope1,
10 atomSet: new Set([atomC, atomD]),
11 scopeName: 'level2',
12})
Both Jotai's Provider and jotai-scope
's scoped provider
are still using global contexts.
If you are developing a library that depends on Jotai and the library user may use Jotai separately in their apps, they can share the same context. This can be troublesome because they point to unexpected Jotai stores.
To avoid conflicting the contexts, a utility function called createIsolation
is exported from jotai-scope
.
1import { createIsolation } from 'jotai-scope' 2 3const { Provider, useStore, useAtom, useAtomValue, useSetAtom } = 4 createIsolation() 5 6function Library() { 7 return ( 8 <Provider> 9 <LibraryComponent /> 10 </Provider> 11 ) 12}
No vulnerabilities found.