react-state-custom 1.0.24 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +17 -1
- package/dist/index.es.js +616 -384
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +21 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/state-utils/createAutoCtx.d.ts +5 -4
- package/dist/state-utils/createRootCtx.d.ts +6 -1
- package/dist/state-utils/ctx.d.ts +1 -0
- package/dist/state-utils/paramsToId.d.ts +1 -0
- package/package.json +21 -5
- package/.github/copilot-instructions.md +0 -57
- package/.github/workflows/deploy.yml +0 -56
- package/.vscode/extensions.json +0 -5
- package/.vscode/settings.json +0 -8
- package/API_DOCUMENTATION.md +0 -1012
- package/dist/dev.d.ts +0 -0
- package/dist/examples/Playground.d.ts +0 -1
- package/dist/examples/cart/app.d.ts +0 -1
- package/dist/examples/cart/index.d.ts +0 -3
- package/dist/examples/cart/state.d.ts +0 -23
- package/dist/examples/cart/view.d.ts +0 -4
- package/dist/examples/counter/app.d.ts +0 -1
- package/dist/examples/counter/index.d.ts +0 -2
- package/dist/examples/counter/state.d.ts +0 -6
- package/dist/examples/counter/view.d.ts +0 -2
- package/dist/examples/form/app.d.ts +0 -1
- package/dist/examples/form/index.d.ts +0 -3
- package/dist/examples/form/state.d.ts +0 -16
- package/dist/examples/form/view.d.ts +0 -4
- package/dist/examples/timer/app.d.ts +0 -1
- package/dist/examples/timer/index.d.ts +0 -2
- package/dist/examples/timer/state.d.ts +0 -11
- package/dist/examples/timer/view.d.ts +0 -4
- package/dist/examples/todo/app.d.ts +0 -1
- package/dist/examples/todo/index.d.ts +0 -3
- package/dist/examples/todo/state.d.ts +0 -17
- package/dist/examples/todo/view.d.ts +0 -4
- package/fix-vscode-yarn-pnp.sh +0 -26
- package/index.html +0 -14
- package/src/dev-tool/DataViewComponent.tsx +0 -17
- package/src/dev-tool/DevTool.css +0 -134
- package/src/dev-tool/DevTool.tsx +0 -20
- package/src/dev-tool/DevToolState.tsx +0 -78
- package/src/dev-tool/StateLabelRender.tsx +0 -38
- package/src/dev-tool/useHighlight.tsx +0 -56
- package/src/dev.tsx +0 -7
- package/src/examples/Playground.tsx +0 -180
- package/src/examples/cart/app.tsx +0 -16
- package/src/examples/cart/index.ts +0 -3
- package/src/examples/cart/state.ts +0 -67
- package/src/examples/cart/view.tsx +0 -62
- package/src/examples/counter/app.tsx +0 -14
- package/src/examples/counter/index.ts +0 -2
- package/src/examples/counter/state.ts +0 -22
- package/src/examples/counter/state.tsx?raw +0 -0
- package/src/examples/counter/view.tsx +0 -20
- package/src/examples/form/app.tsx +0 -16
- package/src/examples/form/index.ts +0 -3
- package/src/examples/form/state.ts +0 -58
- package/src/examples/form/view.tsx +0 -53
- package/src/examples/timer/app.tsx +0 -16
- package/src/examples/timer/index.ts +0 -2
- package/src/examples/timer/state.ts +0 -43
- package/src/examples/timer/view.tsx +0 -26
- package/src/examples/todo/app.tsx +0 -16
- package/src/examples/todo/index.ts +0 -3
- package/src/examples/todo/state.ts +0 -54
- package/src/examples/todo/view.tsx +0 -47
- package/src/index.ts +0 -22
- package/src/state-utils/createAutoCtx.tsx +0 -191
- package/src/state-utils/createRootCtx.tsx +0 -117
- package/src/state-utils/ctx.ts +0 -346
- package/src/state-utils/useArrayHash.ts +0 -53
- package/src/state-utils/useObjectHash.ts +0 -53
- package/src/state-utils/useQuickSubscribe.ts +0 -110
- package/src/state-utils/useRefValue.ts +0 -8
- package/src/state-utils/utils.ts +0 -43
- package/src/vite-env.d.ts +0 -6
- package/tsconfig.json +0 -27
- package/vite.config.dev.ts +0 -16
- package/vite.config.ts +0 -39
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { createRootCtx, createAutoCtx } from '../../index'
|
|
2
|
-
import { useCallback, useState } from 'react'
|
|
3
|
-
|
|
4
|
-
export interface Todo {
|
|
5
|
-
id: string
|
|
6
|
-
text: string
|
|
7
|
-
completed: boolean
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const { useCtxState: useTodoCtx } = createAutoCtx(
|
|
11
|
-
createRootCtx(
|
|
12
|
-
"todos",
|
|
13
|
-
({ listId }: { listId: string }) => {
|
|
14
|
-
const [todos, setTodos] = useState<Todo[]>([])
|
|
15
|
-
const [input, setInput] = useState('')
|
|
16
|
-
|
|
17
|
-
const addTodo = useCallback(() => {
|
|
18
|
-
if (input.trim()) {
|
|
19
|
-
setTodos(prev => [...prev, {
|
|
20
|
-
id: Date.now().toString(),
|
|
21
|
-
text: input.trim(),
|
|
22
|
-
completed: false
|
|
23
|
-
}])
|
|
24
|
-
setInput('')
|
|
25
|
-
}
|
|
26
|
-
}, [input])
|
|
27
|
-
|
|
28
|
-
const toggleTodo = useCallback((id: string) => {
|
|
29
|
-
setTodos(prev => prev.map(t =>
|
|
30
|
-
t.id === id ? { ...t, completed: !t.completed } : t
|
|
31
|
-
))
|
|
32
|
-
}, [])
|
|
33
|
-
|
|
34
|
-
const removeTodo = useCallback((id: string) => {
|
|
35
|
-
setTodos(prev => prev.filter(t => t.id !== id))
|
|
36
|
-
}, [])
|
|
37
|
-
|
|
38
|
-
const clearCompleted = useCallback(() => {
|
|
39
|
-
setTodos(prev => prev.filter(t => !t.completed))
|
|
40
|
-
}, [])
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
listId,
|
|
44
|
-
todos,
|
|
45
|
-
input,
|
|
46
|
-
setInput,
|
|
47
|
-
addTodo,
|
|
48
|
-
toggleTodo,
|
|
49
|
-
removeTodo,
|
|
50
|
-
clearCompleted,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
)
|
|
54
|
-
)
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { useQuickSubscribe } from '../../index'
|
|
2
|
-
import { useTodoCtx } from './state'
|
|
3
|
-
|
|
4
|
-
export const TodoExample = ({ listId = "main" }: { listId?: string }) => {
|
|
5
|
-
const { todos, input, setInput, addTodo, toggleTodo, removeTodo, clearCompleted } =
|
|
6
|
-
useQuickSubscribe(useTodoCtx({ listId }))
|
|
7
|
-
|
|
8
|
-
return (
|
|
9
|
-
<div style={{ padding: '1rem', border: '1px solid #ccc', marginBottom: '1rem' }}>
|
|
10
|
-
<h3>Todo List ({listId})</h3>
|
|
11
|
-
<div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1rem' }}>
|
|
12
|
-
<input
|
|
13
|
-
value={input ?? ''}
|
|
14
|
-
onChange={(e) => setInput?.(e.target.value)}
|
|
15
|
-
onKeyDown={(e) => e.key === 'Enter' && addTodo?.()}
|
|
16
|
-
placeholder="Add todo..."
|
|
17
|
-
style={{ flex: 1, padding: '0.25rem' }}
|
|
18
|
-
/>
|
|
19
|
-
<button onClick={addTodo}>Add</button>
|
|
20
|
-
</div>
|
|
21
|
-
<ul style={{ listStyle: 'none', padding: 0 }}>
|
|
22
|
-
{todos?.map(todo => (
|
|
23
|
-
<li key={todo.id} style={{ display: 'flex', gap: '0.5rem', marginBottom: '0.5rem' }}>
|
|
24
|
-
<input
|
|
25
|
-
type="checkbox"
|
|
26
|
-
checked={todo.completed}
|
|
27
|
-
onChange={() => toggleTodo?.(todo.id)}
|
|
28
|
-
/>
|
|
29
|
-
<span style={{
|
|
30
|
-
flex: 1,
|
|
31
|
-
textDecoration: todo.completed ? 'line-through' : 'none',
|
|
32
|
-
opacity: todo.completed ? 0.6 : 1
|
|
33
|
-
}}>
|
|
34
|
-
{todo.text}
|
|
35
|
-
</span>
|
|
36
|
-
<button onClick={() => removeTodo?.(todo.id)}>×</button>
|
|
37
|
-
</li>
|
|
38
|
-
))}
|
|
39
|
-
</ul>
|
|
40
|
-
{todos?.some(t => t.completed) && (
|
|
41
|
-
<button onClick={clearCompleted}>Clear Completed</button>
|
|
42
|
-
)}
|
|
43
|
-
</div>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export default TodoExample
|
package/src/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// export { default as MyComponent } from './components/MyComponent';
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
Context,
|
|
5
|
-
getContext,
|
|
6
|
-
useDataContext,
|
|
7
|
-
useDataSource,
|
|
8
|
-
useDataSourceMultiple,
|
|
9
|
-
useDataSubscribe,
|
|
10
|
-
useDataSubscribeMultiple,
|
|
11
|
-
useDataSubscribeMultipleWithDebounce,
|
|
12
|
-
useDataSubscribeWithTransform
|
|
13
|
-
} from "./state-utils/ctx"
|
|
14
|
-
|
|
15
|
-
export { createRootCtx } from "./state-utils/createRootCtx"
|
|
16
|
-
export { AutoRootCtx, createAutoCtx } from "./state-utils/createAutoCtx"
|
|
17
|
-
export { useArrayHash } from "./state-utils/useArrayHash"
|
|
18
|
-
|
|
19
|
-
export { useQuickSubscribe } from "./state-utils/useQuickSubscribe"
|
|
20
|
-
|
|
21
|
-
export { DevToolContainer } from "./dev-tool/DevTool"
|
|
22
|
-
export type { DataViewComponent } from "./dev-tool/DataViewComponent"
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, Fragment, useCallback } from "react"
|
|
2
|
-
import { useDataContext, useDataSourceMultiple, useDataSubscribe, type Context } from "./ctx"
|
|
3
|
-
import { createRootCtx } from "./createRootCtx"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const weakmapName = (function () {
|
|
11
|
-
const weakmap = new WeakMap()
|
|
12
|
-
|
|
13
|
-
return (e: any): string => {
|
|
14
|
-
let result = weakmap.get(e);
|
|
15
|
-
if (!result) {
|
|
16
|
-
weakmap.set(e, result = (e?.name ?? "") + Math.random().toString())
|
|
17
|
-
}
|
|
18
|
-
return result
|
|
19
|
-
}
|
|
20
|
-
})()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const resolveName = (e: any) => [
|
|
24
|
-
...Object
|
|
25
|
-
.entries(e ?? {})
|
|
26
|
-
.sort((e, f) => e[0].localeCompare(f[0]))
|
|
27
|
-
.flat()
|
|
28
|
-
].join("-")
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Inline docs: createAutoCtx + AutoRootCtx
|
|
32
|
-
*
|
|
33
|
-
* Quick start
|
|
34
|
-
* 1) Mount <AutoRootCtx /> ONCE near your app root. Provide a Wrapper that acts like an ErrorBoundary to isolate and log errors.
|
|
35
|
-
* Example: <AutoRootCtx Wrapper={MyErrorBoundary} />
|
|
36
|
-
*
|
|
37
|
-
* 2) Create auto contexts from your root context factories:
|
|
38
|
-
* ```
|
|
39
|
-
* const { useCtxState: useTestCtxState } = createAutoCtx(createRootCtx('test-state', stateFn))
|
|
40
|
-
* const { useCtxState: useOtherCtxState } = createAutoCtx(createRootCtx('other-state', otherFn))
|
|
41
|
-
* ```
|
|
42
|
-
* 3) Use them in components:
|
|
43
|
-
* ```
|
|
44
|
-
* const ctx = useTestCtxState({ userId })
|
|
45
|
-
* const { property1, property2 } = useDataSubscribeMultiple(ctx,'property1','property2')
|
|
46
|
-
* // No need to mount the Root returned by createRootCtx directly — AutoRootCtx manages it for you.
|
|
47
|
-
* ```
|
|
48
|
-
* Notes
|
|
49
|
-
* - AutoRootCtx must be mounted before any useCtxState hooks created by createAutoCtx run.
|
|
50
|
-
* - Wrapper should be an ErrorBoundary-like component that simply renders {children}; no extra providers or layout required.
|
|
51
|
-
* - For each unique params object (by stable stringified key), AutoRootCtx ensures a corresponding Root instance is rendered.
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
export const AutoRootCtx = ({ Wrapper = Fragment }) => {
|
|
55
|
-
|
|
56
|
-
const ctx = useDataContext<any>("auto-ctx")
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const [state, setState] = useState<Record<string, { Component: React.FC, subState: Record<string, { params: any, counter: number }> }>>({})
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const subscribeRoot = useCallback(
|
|
63
|
-
(Comp: any, params: any) => {
|
|
64
|
-
const weakName = weakmapName(Comp);
|
|
65
|
-
const key = resolveName(params);
|
|
66
|
-
|
|
67
|
-
setState(({
|
|
68
|
-
[weakName]: {
|
|
69
|
-
Component = Comp,
|
|
70
|
-
subState: {
|
|
71
|
-
[key]: preState = { params, counter: 0 },
|
|
72
|
-
...subState
|
|
73
|
-
} = {}
|
|
74
|
-
} = {},
|
|
75
|
-
...state
|
|
76
|
-
}) => ({
|
|
77
|
-
...state,
|
|
78
|
-
[weakName]: {
|
|
79
|
-
Component,
|
|
80
|
-
subState: {
|
|
81
|
-
...subState,
|
|
82
|
-
[key]: {
|
|
83
|
-
...preState,
|
|
84
|
-
counter: preState.counter + 1,
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
}
|
|
88
|
-
}));
|
|
89
|
-
|
|
90
|
-
return () => setState(({
|
|
91
|
-
[weakName]: {
|
|
92
|
-
Component = Comp,
|
|
93
|
-
subState: {
|
|
94
|
-
[key]: preState = { params, counter: 0 },
|
|
95
|
-
...subState
|
|
96
|
-
} = {}
|
|
97
|
-
} = {},
|
|
98
|
-
...state
|
|
99
|
-
}) => ({
|
|
100
|
-
...state,
|
|
101
|
-
[weakName]: {
|
|
102
|
-
Component,
|
|
103
|
-
subState: {
|
|
104
|
-
...subState,
|
|
105
|
-
...preState.counter > 1 ? {
|
|
106
|
-
[key]: {
|
|
107
|
-
...preState,
|
|
108
|
-
counter: preState.counter - 1,
|
|
109
|
-
},
|
|
110
|
-
} : {},
|
|
111
|
-
},
|
|
112
|
-
}
|
|
113
|
-
}))
|
|
114
|
-
|
|
115
|
-
},
|
|
116
|
-
[]
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
useDataSourceMultiple(ctx,
|
|
120
|
-
["subscribe", subscribeRoot],
|
|
121
|
-
["state", state],
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return <>
|
|
126
|
-
{Object.entries(state)
|
|
127
|
-
.flatMap(([k1, { Component, subState }]) => Object
|
|
128
|
-
.entries(subState)
|
|
129
|
-
.map(([k2, { counter, params }]) => ({ key: k1 + k2, Component, params, counter }))
|
|
130
|
-
.filter(e => e.counter > 0)
|
|
131
|
-
.map(({ key, params, Component }) => <Wrapper key={key} >
|
|
132
|
-
<Component {...params} />
|
|
133
|
-
</Wrapper>)
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
</>
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* createAutoCtx
|
|
142
|
-
*
|
|
143
|
-
* Bridges a Root context (from createRootCtx) to the global AutoRootCtx renderer.
|
|
144
|
-
* You do NOT mount the Root component yourself — just mount <AutoRootCtx /> once at the app root.
|
|
145
|
-
*
|
|
146
|
-
* Usage:
|
|
147
|
-
* ```
|
|
148
|
-
* const { useCtxState: useTestCtxState } = createAutoCtx(createRootCtx(
|
|
149
|
-
* 'test-state',
|
|
150
|
-
* stateFn
|
|
151
|
-
* ))
|
|
152
|
-
* const { useCtxState: useOtherCtxState } = createAutoCtx(createRootCtx(
|
|
153
|
-
* 'other-state',
|
|
154
|
-
* otherFn
|
|
155
|
-
* ))
|
|
156
|
-
* ```
|
|
157
|
-
*
|
|
158
|
-
* Then inside components:
|
|
159
|
-
* ```
|
|
160
|
-
* const ctxState = useTestCtxState({ any: 'params' })
|
|
161
|
-
* ```
|
|
162
|
-
* AutoRootCtx will subscribe/unsubscribe instances per unique params and render the appropriate Root under the hood.
|
|
163
|
-
*/
|
|
164
|
-
export const createAutoCtx = <U extends object, V extends object,>(
|
|
165
|
-
{ Root, useCtxState, useCtxStateStrict, resolveCtxName }: ReturnType<typeof createRootCtx<U, V>>,
|
|
166
|
-
unmountTime = 0
|
|
167
|
-
) => {
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
|
|
171
|
-
useCtxState: (e: U): Context<V> => {
|
|
172
|
-
|
|
173
|
-
const ctxName = resolveCtxName(e)
|
|
174
|
-
|
|
175
|
-
const subscribe = useDataSubscribe(useDataContext<any>("auto-ctx"), "subscribe")
|
|
176
|
-
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
// Subscribe this component to an AutoRootCtx-managed Root instance keyed by e.
|
|
179
|
-
// AutoRootCtx handles instance ref-counting and cleanup on unmount.
|
|
180
|
-
if (unmountTime == 0) {
|
|
181
|
-
return subscribe?.(Root, e)
|
|
182
|
-
} else {
|
|
183
|
-
let unsub = subscribe?.(Root, e)
|
|
184
|
-
return () => setTimeout(unsub, unmountTime)
|
|
185
|
-
}
|
|
186
|
-
}, [subscribe, ctxName])
|
|
187
|
-
|
|
188
|
-
return useDataContext<V>(ctxName)
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo } from "react"
|
|
2
|
-
import { useDataContext, useDataSourceMultiple, type Context } from "./ctx"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* createRootCtx
|
|
8
|
-
*
|
|
9
|
-
* Factory that creates a headless "Root" component and companion hooks for a context namespace.
|
|
10
|
-
* It derives a unique context name from a base `name` and a props object `U`, then publishes
|
|
11
|
-
* a computed state `V` (from `useFn`) to that context.
|
|
12
|
-
*
|
|
13
|
-
* Usage (manual mounting):
|
|
14
|
-
* ```
|
|
15
|
-
* const { Root, useCtxState } = createRootCtx('user-state', useUserState)
|
|
16
|
-
* ...
|
|
17
|
-
* // Mount exactly one Root per unique props combination
|
|
18
|
-
* <Root userId={id} />
|
|
19
|
-
* ...
|
|
20
|
-
* // Read anywhere ,using the same props shape
|
|
21
|
-
* const user = useCtxState({ userId: id })
|
|
22
|
-
*```
|
|
23
|
-
* Strict vs lenient consumers:
|
|
24
|
-
* - useCtxStateStrict(props) throws if a matching Root is not mounted.
|
|
25
|
-
* - useCtxState(props) logs an error (after 1s) instead of throwing.
|
|
26
|
-
*
|
|
27
|
-
* Multiple instances safety:
|
|
28
|
-
* - Mounting more than one Root with the same resolved context name throws (guards accidental duplicates).
|
|
29
|
-
*
|
|
30
|
-
* Name resolution notes:
|
|
31
|
-
* - The context name is built from `name` + sorted key/value pairs of `props` (U), joined by "-".
|
|
32
|
-
* - Prefer stable, primitive props to avoid collisions; if you need automation, pair with `createAutoCtx` and
|
|
33
|
-
* mount a single <AutoRootCtx Wrapper={ErrorBoundary} /> at the app root so you don't manually mount `Root`.
|
|
34
|
-
*/
|
|
35
|
-
export const createRootCtx = <U extends object, V extends object>(name: string, useFn: (e: U) => V) => {
|
|
36
|
-
|
|
37
|
-
const resolveCtxName = (e: U) => [
|
|
38
|
-
name,
|
|
39
|
-
...Object
|
|
40
|
-
.entries(e ?? {})
|
|
41
|
-
.sort((e, f) => e[0].localeCompare(f[0]))
|
|
42
|
-
.flat()
|
|
43
|
-
].join("-")
|
|
44
|
-
|
|
45
|
-
let ctxMountedCheck = new Set<string>()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const RootState: React.FC<U> = (e: U) => {
|
|
49
|
-
const state = useFn(e)
|
|
50
|
-
const ctxName = resolveCtxName(e)
|
|
51
|
-
const ctx = useDataContext<V>(ctxName)
|
|
52
|
-
const stack = useMemo(() => new Error().stack, [])
|
|
53
|
-
|
|
54
|
-
useDataSourceMultiple(
|
|
55
|
-
ctx,
|
|
56
|
-
...Object.entries(state) as any
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (ctxMountedCheck.has(ctxName)) {
|
|
61
|
-
const err = new Error("RootContext " + ctxName + " are mounted more than once")
|
|
62
|
-
err.stack = stack;
|
|
63
|
-
throw err
|
|
64
|
-
}
|
|
65
|
-
ctxMountedCheck.add(ctxName)
|
|
66
|
-
return () => { ctxMountedCheck.delete(ctxName) };
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
return <></>
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
RootState.displayName = `State[${useFn?.name??'??'}]`
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
resolveCtxName,
|
|
76
|
-
Root: RootState,
|
|
77
|
-
/**
|
|
78
|
-
* Strict consumer: throws if the corresponding Root for these props isn't mounted.
|
|
79
|
-
* Use in development/tests to fail fast when wiring is incorrect.
|
|
80
|
-
*/
|
|
81
|
-
useCtxStateStrict: (e: U): Context<V> => {
|
|
82
|
-
const ctxName = resolveCtxName(e)
|
|
83
|
-
|
|
84
|
-
const stack = useMemo(() => new Error().stack, [])
|
|
85
|
-
|
|
86
|
-
useEffect(() => {
|
|
87
|
-
if (!ctxMountedCheck.has(ctxName)) {
|
|
88
|
-
const err = new Error("RootContext [" + ctxName + "] is not mounted")
|
|
89
|
-
err.stack = stack;
|
|
90
|
-
throw err
|
|
91
|
-
}
|
|
92
|
-
}, [ctxName])
|
|
93
|
-
|
|
94
|
-
return useDataContext<V>(ctxName)
|
|
95
|
-
},
|
|
96
|
-
/**
|
|
97
|
-
* Lenient consumer: schedules a console.error if the Root isn't mounted instead of throwing.
|
|
98
|
-
* Useful in production to avoid hard crashes while still surfacing misconfiguration.
|
|
99
|
-
*/
|
|
100
|
-
useCtxState: (e: U): Context<V> => {
|
|
101
|
-
const ctxName = resolveCtxName(e)
|
|
102
|
-
|
|
103
|
-
const stack = useMemo(() => new Error().stack, [])
|
|
104
|
-
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (!ctxMountedCheck.has(ctxName)) {
|
|
107
|
-
const err = new Error("RootContext [" + ctxName + "] is not mounted")
|
|
108
|
-
err.stack = stack;
|
|
109
|
-
let timeout = setTimeout(() => console.error(err), 1000)
|
|
110
|
-
return () => clearTimeout(timeout)
|
|
111
|
-
}
|
|
112
|
-
}, [ctxMountedCheck.has(ctxName)])
|
|
113
|
-
|
|
114
|
-
return useDataContext<V>(ctxName)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|