@depup/react-redux 9.3.0-depup.53
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.md +21 -0
- package/README.md +32 -0
- package/changes.json +14 -0
- package/dist/cjs/index.js +6 -0
- package/dist/cjs/react-redux.development.cjs +1119 -0
- package/dist/cjs/react-redux.development.cjs.map +1 -0
- package/dist/cjs/react-redux.production.min.cjs +6 -0
- package/dist/cjs/react-redux.production.min.cjs.map +1 -0
- package/dist/react-redux.browser.mjs +6 -0
- package/dist/react-redux.browser.mjs.map +1 -0
- package/dist/react-redux.d.ts +587 -0
- package/dist/react-redux.legacy-esm.js +1105 -0
- package/dist/react-redux.legacy-esm.js.map +1 -0
- package/dist/react-redux.mjs +1071 -0
- package/dist/react-redux.mjs.map +1 -0
- package/dist/rsc.mjs +46 -0
- package/dist/rsc.mjs.map +1 -0
- package/package.json +124 -0
- package/src/components/Context.ts +50 -0
- package/src/components/Provider.tsx +105 -0
- package/src/components/connect.tsx +845 -0
- package/src/connect/invalidArgFactory.ts +14 -0
- package/src/connect/mapDispatchToProps.ts +25 -0
- package/src/connect/mapStateToProps.ts +14 -0
- package/src/connect/mergeProps.ts +78 -0
- package/src/connect/selectorFactory.ts +242 -0
- package/src/connect/verifySubselectors.ts +26 -0
- package/src/connect/wrapMapToProps.ts +110 -0
- package/src/exports.ts +51 -0
- package/src/hooks/useDispatch.ts +104 -0
- package/src/hooks/useReduxContext.ts +42 -0
- package/src/hooks/useSelector.ts +286 -0
- package/src/hooks/useStore.ts +123 -0
- package/src/index-rsc.ts +35 -0
- package/src/index.ts +1 -0
- package/src/types.ts +180 -0
- package/src/utils/Subscription.ts +183 -0
- package/src/utils/batch.ts +4 -0
- package/src/utils/bindActionCreators.ts +16 -0
- package/src/utils/hoistStatics.ts +139 -0
- package/src/utils/isPlainObject.ts +17 -0
- package/src/utils/react-is.ts +97 -0
- package/src/utils/react.ts +3 -0
- package/src/utils/shallowEqual.ts +36 -0
- package/src/utils/useIsomorphicLayoutEffect.ts +40 -0
- package/src/utils/useSyncExternalStore.ts +9 -0
- package/src/utils/verifyPlainObject.ts +14 -0
- package/src/utils/warning.ts +21 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { React } from '../utils/react'
|
|
2
|
+
import { ReactReduxContext } from '../components/Context'
|
|
3
|
+
import type { ReactReduxContextValue } from '../components/Context'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook factory, which creates a `useReduxContext` hook bound to a given context. This is a low-level
|
|
7
|
+
* hook that you should usually not need to call directly.
|
|
8
|
+
*
|
|
9
|
+
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
|
|
10
|
+
* @returns {Function} A `useReduxContext` hook bound to the specified context.
|
|
11
|
+
*/
|
|
12
|
+
export function createReduxContextHook(context = ReactReduxContext) {
|
|
13
|
+
return function useReduxContext(): ReactReduxContextValue {
|
|
14
|
+
const contextValue = React.useContext(context)
|
|
15
|
+
|
|
16
|
+
if (process.env.NODE_ENV !== 'production' && !contextValue) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'could not find react-redux context value; please ensure the component is wrapped in a <Provider>',
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return contextValue!
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A hook to access the value of the `ReactReduxContext`. This is a low-level
|
|
28
|
+
* hook that you should usually not need to call directly.
|
|
29
|
+
*
|
|
30
|
+
* @returns {any} the value of the `ReactReduxContext`
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
*
|
|
34
|
+
* import React from 'react'
|
|
35
|
+
* import { useReduxContext } from 'react-redux'
|
|
36
|
+
*
|
|
37
|
+
* export const CounterComponent = () => {
|
|
38
|
+
* const { store } = useReduxContext()
|
|
39
|
+
* return <div>{store.getState()}</div>
|
|
40
|
+
* }
|
|
41
|
+
*/
|
|
42
|
+
export const useReduxContext = /*#__PURE__*/ createReduxContextHook()
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
//import * as React from 'react'
|
|
2
|
+
import { React } from '../utils/react'
|
|
3
|
+
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'
|
|
4
|
+
import type { ReactReduxContextValue } from '../components/Context'
|
|
5
|
+
import { ReactReduxContext } from '../components/Context'
|
|
6
|
+
import type { EqualityFn, NoInfer } from '../types'
|
|
7
|
+
import {
|
|
8
|
+
createReduxContextHook,
|
|
9
|
+
useReduxContext as useDefaultReduxContext,
|
|
10
|
+
} from './useReduxContext'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The frequency of development mode checks.
|
|
14
|
+
*
|
|
15
|
+
* @since 8.1.0
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export type DevModeCheckFrequency = 'never' | 'once' | 'always'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Represents the configuration for development mode checks.
|
|
22
|
+
*
|
|
23
|
+
* @since 9.0.0
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export interface DevModeChecks {
|
|
27
|
+
/**
|
|
28
|
+
* Overrides the global stability check for the selector.
|
|
29
|
+
* - `once` - Run only the first time the selector is called.
|
|
30
|
+
* - `always` - Run every time the selector is called.
|
|
31
|
+
* - `never` - Never run the stability check.
|
|
32
|
+
*
|
|
33
|
+
* @default 'once'
|
|
34
|
+
*
|
|
35
|
+
* @since 8.1.0
|
|
36
|
+
*/
|
|
37
|
+
stabilityCheck: DevModeCheckFrequency
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Overrides the global identity function check for the selector.
|
|
41
|
+
* - `once` - Run only the first time the selector is called.
|
|
42
|
+
* - `always` - Run every time the selector is called.
|
|
43
|
+
* - `never` - Never run the identity function check.
|
|
44
|
+
*
|
|
45
|
+
* **Note**: Previously referred to as `noopCheck`.
|
|
46
|
+
*
|
|
47
|
+
* @default 'once'
|
|
48
|
+
*
|
|
49
|
+
* @since 9.0.0
|
|
50
|
+
*/
|
|
51
|
+
identityFunctionCheck: DevModeCheckFrequency
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface UseSelectorOptions<Selected = unknown> {
|
|
55
|
+
equalityFn?: EqualityFn<Selected>
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* `useSelector` performs additional checks in development mode to help
|
|
59
|
+
* identify and warn about potential issues in selector behavior. This
|
|
60
|
+
* option allows you to customize the behavior of these checks per selector.
|
|
61
|
+
*
|
|
62
|
+
* @since 9.0.0
|
|
63
|
+
*/
|
|
64
|
+
devModeChecks?: Partial<DevModeChecks>
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Represents a custom hook that allows you to extract data from the
|
|
69
|
+
* Redux store state, using a selector function. The selector function
|
|
70
|
+
* takes the current state as an argument and returns a part of the state
|
|
71
|
+
* or some derived data. The hook also supports an optional equality
|
|
72
|
+
* function or options object to customize its behavior.
|
|
73
|
+
*
|
|
74
|
+
* @template StateType - The specific type of state this hook operates on.
|
|
75
|
+
*
|
|
76
|
+
* @public
|
|
77
|
+
*/
|
|
78
|
+
export interface UseSelector<StateType = unknown> {
|
|
79
|
+
/**
|
|
80
|
+
* A function that takes a selector function as its first argument.
|
|
81
|
+
* The selector function is responsible for selecting a part of
|
|
82
|
+
* the Redux store's state or computing derived data.
|
|
83
|
+
*
|
|
84
|
+
* @param selector - A function that receives the current state and returns a part of the state or some derived data.
|
|
85
|
+
* @param equalityFnOrOptions - An optional equality function or options object for customizing the behavior of the selector.
|
|
86
|
+
* @returns The selected part of the state or derived data.
|
|
87
|
+
*
|
|
88
|
+
* @template TState - The specific type of state this hook operates on.
|
|
89
|
+
* @template Selected - The type of the value that the selector function will return.
|
|
90
|
+
*/
|
|
91
|
+
<TState extends StateType = StateType, Selected = unknown>(
|
|
92
|
+
selector: (state: TState) => Selected,
|
|
93
|
+
equalityFnOrOptions?: EqualityFn<Selected> | UseSelectorOptions<Selected>,
|
|
94
|
+
): Selected
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Creates a "pre-typed" version of {@linkcode useSelector useSelector}
|
|
98
|
+
* where the `state` type is predefined.
|
|
99
|
+
*
|
|
100
|
+
* This allows you to set the `state` type once, eliminating the need to
|
|
101
|
+
* specify it with every {@linkcode useSelector useSelector} call.
|
|
102
|
+
*
|
|
103
|
+
* @returns A pre-typed `useSelector` with the state type already defined.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* export const useAppSelector = useSelector.withTypes<RootState>()
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @template OverrideStateType - The specific type of state this hook operates on.
|
|
111
|
+
*
|
|
112
|
+
* @since 9.1.0
|
|
113
|
+
*/
|
|
114
|
+
withTypes: <
|
|
115
|
+
OverrideStateType extends StateType,
|
|
116
|
+
>() => UseSelector<OverrideStateType>
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const refEquality: EqualityFn<any> = (a, b) => a === b
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Hook factory, which creates a `useSelector` hook bound to a given context.
|
|
123
|
+
*
|
|
124
|
+
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
|
|
125
|
+
* @returns {Function} A `useSelector` hook bound to the specified context.
|
|
126
|
+
*/
|
|
127
|
+
export function createSelectorHook(
|
|
128
|
+
context: React.Context<ReactReduxContextValue<
|
|
129
|
+
any,
|
|
130
|
+
any
|
|
131
|
+
> | null> = ReactReduxContext,
|
|
132
|
+
): UseSelector {
|
|
133
|
+
const useReduxContext =
|
|
134
|
+
context === ReactReduxContext
|
|
135
|
+
? useDefaultReduxContext
|
|
136
|
+
: createReduxContextHook(context)
|
|
137
|
+
|
|
138
|
+
const useSelector = <TState, Selected>(
|
|
139
|
+
selector: (state: TState) => Selected,
|
|
140
|
+
equalityFnOrOptions:
|
|
141
|
+
| EqualityFn<NoInfer<Selected>>
|
|
142
|
+
| UseSelectorOptions<NoInfer<Selected>> = {},
|
|
143
|
+
): Selected => {
|
|
144
|
+
const { equalityFn = refEquality } =
|
|
145
|
+
typeof equalityFnOrOptions === 'function'
|
|
146
|
+
? { equalityFn: equalityFnOrOptions }
|
|
147
|
+
: equalityFnOrOptions
|
|
148
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
149
|
+
if (!selector) {
|
|
150
|
+
throw new Error(`You must pass a selector to useSelector`)
|
|
151
|
+
}
|
|
152
|
+
if (typeof selector !== 'function') {
|
|
153
|
+
throw new Error(`You must pass a function as a selector to useSelector`)
|
|
154
|
+
}
|
|
155
|
+
if (typeof equalityFn !== 'function') {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`You must pass a function as an equality function to useSelector`,
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const reduxContext = useReduxContext()
|
|
163
|
+
|
|
164
|
+
const { store, subscription, getServerState } = reduxContext
|
|
165
|
+
|
|
166
|
+
const firstRun = React.useRef(true)
|
|
167
|
+
|
|
168
|
+
const wrappedSelector = React.useCallback<typeof selector>(
|
|
169
|
+
{
|
|
170
|
+
[selector.name](state: TState) {
|
|
171
|
+
const selected = selector(state)
|
|
172
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
173
|
+
const { devModeChecks = {} } =
|
|
174
|
+
typeof equalityFnOrOptions === 'function'
|
|
175
|
+
? {}
|
|
176
|
+
: equalityFnOrOptions
|
|
177
|
+
const { identityFunctionCheck, stabilityCheck } = reduxContext
|
|
178
|
+
const {
|
|
179
|
+
identityFunctionCheck: finalIdentityFunctionCheck,
|
|
180
|
+
stabilityCheck: finalStabilityCheck,
|
|
181
|
+
} = {
|
|
182
|
+
stabilityCheck,
|
|
183
|
+
identityFunctionCheck,
|
|
184
|
+
...devModeChecks,
|
|
185
|
+
}
|
|
186
|
+
if (
|
|
187
|
+
finalStabilityCheck === 'always' ||
|
|
188
|
+
(finalStabilityCheck === 'once' && firstRun.current)
|
|
189
|
+
) {
|
|
190
|
+
const toCompare = selector(state)
|
|
191
|
+
if (!equalityFn(selected, toCompare)) {
|
|
192
|
+
let stack: string | undefined = undefined
|
|
193
|
+
try {
|
|
194
|
+
throw new Error()
|
|
195
|
+
} catch (e) {
|
|
196
|
+
// eslint-disable-next-line no-extra-semi
|
|
197
|
+
;({ stack } = e as Error)
|
|
198
|
+
}
|
|
199
|
+
console.warn(
|
|
200
|
+
'Selector ' +
|
|
201
|
+
(selector.name || 'unknown') +
|
|
202
|
+
' returned a different result when called with the same parameters. This can lead to unnecessary rerenders.' +
|
|
203
|
+
'\nSelectors that return a new reference (such as an object or an array) should be memoized: https://redux.js.org/usage/deriving-data-selectors#optimizing-selectors-with-memoization',
|
|
204
|
+
{
|
|
205
|
+
state,
|
|
206
|
+
selected,
|
|
207
|
+
selected2: toCompare,
|
|
208
|
+
stack,
|
|
209
|
+
},
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (
|
|
214
|
+
finalIdentityFunctionCheck === 'always' ||
|
|
215
|
+
(finalIdentityFunctionCheck === 'once' && firstRun.current)
|
|
216
|
+
) {
|
|
217
|
+
// @ts-ignore
|
|
218
|
+
if (selected === state) {
|
|
219
|
+
let stack: string | undefined = undefined
|
|
220
|
+
try {
|
|
221
|
+
throw new Error()
|
|
222
|
+
} catch (e) {
|
|
223
|
+
// eslint-disable-next-line no-extra-semi
|
|
224
|
+
;({ stack } = e as Error)
|
|
225
|
+
}
|
|
226
|
+
console.warn(
|
|
227
|
+
'Selector ' +
|
|
228
|
+
(selector.name || 'unknown') +
|
|
229
|
+
' returned the root state when called. This can lead to unnecessary rerenders.' +
|
|
230
|
+
'\nSelectors that return the entire state are almost certainly a mistake, as they will cause a rerender whenever *anything* in state changes.',
|
|
231
|
+
{ stack },
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (firstRun.current) firstRun.current = false
|
|
236
|
+
}
|
|
237
|
+
return selected
|
|
238
|
+
},
|
|
239
|
+
}[selector.name],
|
|
240
|
+
[selector],
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
const selectedState = useSyncExternalStoreWithSelector(
|
|
244
|
+
subscription.addNestedSub,
|
|
245
|
+
store.getState,
|
|
246
|
+
getServerState || store.getState,
|
|
247
|
+
wrappedSelector,
|
|
248
|
+
equalityFn,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
React.useDebugValue(selectedState)
|
|
252
|
+
|
|
253
|
+
return selectedState
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
Object.assign(useSelector, {
|
|
257
|
+
withTypes: () => useSelector,
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
return useSelector as UseSelector
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* A hook to access the redux store's state. This hook takes a selector function
|
|
265
|
+
* as an argument. The selector is called with the store state.
|
|
266
|
+
*
|
|
267
|
+
* This hook takes an optional equality comparison function as the second parameter
|
|
268
|
+
* that allows you to customize the way the selected state is compared to determine
|
|
269
|
+
* whether the component needs to be re-rendered.
|
|
270
|
+
*
|
|
271
|
+
* @param {Function} selector the selector function
|
|
272
|
+
* @param {Function=} equalityFn the function that will be used to determine equality
|
|
273
|
+
*
|
|
274
|
+
* @returns {any} the selected state
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
*
|
|
278
|
+
* import React from 'react'
|
|
279
|
+
* import { useSelector } from 'react-redux'
|
|
280
|
+
*
|
|
281
|
+
* export const CounterComponent = () => {
|
|
282
|
+
* const counter = useSelector(state => state.counter)
|
|
283
|
+
* return <div>{counter}</div>
|
|
284
|
+
* }
|
|
285
|
+
*/
|
|
286
|
+
export const useSelector = /*#__PURE__*/ createSelectorHook()
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { Context } from 'react'
|
|
2
|
+
import type { Action, Store } from 'redux'
|
|
3
|
+
import type { ReactReduxContextValue } from '../components/Context'
|
|
4
|
+
import { ReactReduxContext } from '../components/Context'
|
|
5
|
+
import {
|
|
6
|
+
createReduxContextHook,
|
|
7
|
+
useReduxContext as useDefaultReduxContext,
|
|
8
|
+
} from './useReduxContext'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents a type that extracts the action type from a given Redux store.
|
|
12
|
+
*
|
|
13
|
+
* @template StoreType - The specific type of the Redux store.
|
|
14
|
+
*
|
|
15
|
+
* @since 9.1.0
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export type ExtractStoreActionType<StoreType extends Store> =
|
|
19
|
+
StoreType extends Store<any, infer ActionType> ? ActionType : never
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Represents a custom hook that provides access to the Redux store.
|
|
23
|
+
*
|
|
24
|
+
* @template StoreType - The specific type of the Redux store that gets returned.
|
|
25
|
+
*
|
|
26
|
+
* @since 9.1.0
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export interface UseStore<StoreType extends Store> {
|
|
30
|
+
/**
|
|
31
|
+
* Returns the Redux store instance.
|
|
32
|
+
*
|
|
33
|
+
* @returns The Redux store instance.
|
|
34
|
+
*/
|
|
35
|
+
(): StoreType
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns the Redux store instance with specific state and action types.
|
|
39
|
+
*
|
|
40
|
+
* @returns The Redux store with the specified state and action types.
|
|
41
|
+
*
|
|
42
|
+
* @template StateType - The specific type of the state used in the store.
|
|
43
|
+
* @template ActionType - The specific type of the actions used in the store.
|
|
44
|
+
*/
|
|
45
|
+
<
|
|
46
|
+
StateType extends ReturnType<StoreType['getState']> = ReturnType<
|
|
47
|
+
StoreType['getState']
|
|
48
|
+
>,
|
|
49
|
+
ActionType extends Action = ExtractStoreActionType<Store>,
|
|
50
|
+
>(): Store<StateType, ActionType>
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates a "pre-typed" version of {@linkcode useStore useStore}
|
|
54
|
+
* where the type of the Redux `store` is predefined.
|
|
55
|
+
*
|
|
56
|
+
* This allows you to set the `store` type once, eliminating the need to
|
|
57
|
+
* specify it with every {@linkcode useStore useStore} call.
|
|
58
|
+
*
|
|
59
|
+
* @returns A pre-typed `useStore` with the store type already defined.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* export const useAppStore = useStore.withTypes<AppStore>()
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @template OverrideStoreType - The specific type of the Redux store that gets returned.
|
|
67
|
+
*
|
|
68
|
+
* @since 9.1.0
|
|
69
|
+
*/
|
|
70
|
+
withTypes: <
|
|
71
|
+
OverrideStoreType extends StoreType,
|
|
72
|
+
>() => UseStore<OverrideStoreType>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Hook factory, which creates a `useStore` hook bound to a given context.
|
|
77
|
+
*
|
|
78
|
+
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
|
|
79
|
+
* @returns {Function} A `useStore` hook bound to the specified context.
|
|
80
|
+
*/
|
|
81
|
+
export function createStoreHook<
|
|
82
|
+
StateType = unknown,
|
|
83
|
+
ActionType extends Action = Action,
|
|
84
|
+
>(
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
context?: Context<ReactReduxContextValue<
|
|
87
|
+
StateType,
|
|
88
|
+
ActionType
|
|
89
|
+
> | null> = ReactReduxContext,
|
|
90
|
+
) {
|
|
91
|
+
const useReduxContext =
|
|
92
|
+
context === ReactReduxContext
|
|
93
|
+
? useDefaultReduxContext
|
|
94
|
+
: // @ts-ignore
|
|
95
|
+
createReduxContextHook(context)
|
|
96
|
+
const useStore = () => {
|
|
97
|
+
const { store } = useReduxContext()
|
|
98
|
+
return store
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Object.assign(useStore, {
|
|
102
|
+
withTypes: () => useStore,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
return useStore as UseStore<Store<StateType, ActionType>>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A hook to access the redux store.
|
|
110
|
+
*
|
|
111
|
+
* @returns {any} the redux store
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
*
|
|
115
|
+
* import React from 'react'
|
|
116
|
+
* import { useStore } from 'react-redux'
|
|
117
|
+
*
|
|
118
|
+
* export const ExampleComponent = () => {
|
|
119
|
+
* const store = useStore()
|
|
120
|
+
* return <div>{store.getState()}</div>
|
|
121
|
+
* }
|
|
122
|
+
*/
|
|
123
|
+
export const useStore = /*#__PURE__*/ createStoreHook()
|
package/src/index-rsc.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type * as normal from './index'
|
|
2
|
+
import type * as rsc from './index-rsc'
|
|
3
|
+
|
|
4
|
+
// checks to make sure we didn't forgot to replicate any exports
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
7
|
+
const _check: typeof normal = {} as typeof rsc
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
9
|
+
const _check2: typeof rsc = {} as typeof normal
|
|
10
|
+
|
|
11
|
+
// -------------------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
const throwNotSupportedError = ((
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
15
|
+
...args: any[]
|
|
16
|
+
): any => {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'This function is not supported in React Server Components. Please only use this export in a Client Component.',
|
|
19
|
+
)
|
|
20
|
+
}) as any
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
throwNotSupportedError as Provider,
|
|
24
|
+
throwNotSupportedError as batch,
|
|
25
|
+
throwNotSupportedError as connect,
|
|
26
|
+
throwNotSupportedError as legacy_connect,
|
|
27
|
+
throwNotSupportedError as createDispatchHook,
|
|
28
|
+
throwNotSupportedError as createSelectorHook,
|
|
29
|
+
throwNotSupportedError as createStoreHook,
|
|
30
|
+
throwNotSupportedError as useDispatch,
|
|
31
|
+
throwNotSupportedError as useSelector,
|
|
32
|
+
throwNotSupportedError as useStore,
|
|
33
|
+
}
|
|
34
|
+
export const ReactReduxContext = {} as any
|
|
35
|
+
export { default as shallowEqual } from './utils/shallowEqual'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './exports'
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ClassAttributes,
|
|
3
|
+
ComponentClass,
|
|
4
|
+
ComponentType,
|
|
5
|
+
FunctionComponent,
|
|
6
|
+
JSX,
|
|
7
|
+
} from 'react'
|
|
8
|
+
|
|
9
|
+
import type { Action, UnknownAction, Dispatch } from 'redux'
|
|
10
|
+
|
|
11
|
+
import type { NonReactStatics } from './utils/hoistStatics'
|
|
12
|
+
|
|
13
|
+
import type { ConnectProps } from './components/connect'
|
|
14
|
+
|
|
15
|
+
import type { UseSelectorOptions } from './hooks/useSelector'
|
|
16
|
+
|
|
17
|
+
export type FixTypeLater = any
|
|
18
|
+
|
|
19
|
+
export type EqualityFn<T> = (a: T, b: T) => boolean
|
|
20
|
+
|
|
21
|
+
export type ExtendedEqualityFn<T, P> = (a: T, b: T, c: P, d: P) => boolean
|
|
22
|
+
|
|
23
|
+
export type AnyIfEmpty<T extends object> = keyof T extends never ? any : T
|
|
24
|
+
|
|
25
|
+
export type DistributiveOmit<T, K extends keyof T> = T extends unknown
|
|
26
|
+
? Omit<T, K>
|
|
27
|
+
: never
|
|
28
|
+
|
|
29
|
+
export interface DispatchProp<A extends Action<string> = UnknownAction> {
|
|
30
|
+
dispatch: Dispatch<A>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A property P will be present if:
|
|
35
|
+
* - it is present in DecorationTargetProps
|
|
36
|
+
*
|
|
37
|
+
* Its value will be dependent on the following conditions
|
|
38
|
+
* - if property P is present in InjectedProps and its definition extends the definition
|
|
39
|
+
* in DecorationTargetProps, then its definition will be that of DecorationTargetProps[P]
|
|
40
|
+
* - if property P is not present in InjectedProps then its definition will be that of
|
|
41
|
+
* DecorationTargetProps[P]
|
|
42
|
+
* - if property P is present in InjectedProps but does not extend the
|
|
43
|
+
* DecorationTargetProps[P] definition, its definition will be that of InjectedProps[P]
|
|
44
|
+
*/
|
|
45
|
+
export type Matching<InjectedProps, DecorationTargetProps> = {
|
|
46
|
+
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
|
|
47
|
+
? InjectedProps[P] extends DecorationTargetProps[P]
|
|
48
|
+
? DecorationTargetProps[P]
|
|
49
|
+
: InjectedProps[P]
|
|
50
|
+
: DecorationTargetProps[P]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* a property P will be present if :
|
|
55
|
+
* - it is present in both DecorationTargetProps and InjectedProps
|
|
56
|
+
* - InjectedProps[P] can satisfy DecorationTargetProps[P]
|
|
57
|
+
* ie: decorated component can accept more types than decorator is injecting
|
|
58
|
+
*
|
|
59
|
+
* For decoration, inject props or ownProps are all optionally
|
|
60
|
+
* required by the decorated (right hand side) component.
|
|
61
|
+
* But any property required by the decorated component must be satisfied by the injected property.
|
|
62
|
+
*/
|
|
63
|
+
export type Shared<InjectedProps, DecorationTargetProps> = {
|
|
64
|
+
[P in Extract<
|
|
65
|
+
keyof InjectedProps,
|
|
66
|
+
keyof DecorationTargetProps
|
|
67
|
+
>]?: InjectedProps[P] extends DecorationTargetProps[P]
|
|
68
|
+
? DecorationTargetProps[P]
|
|
69
|
+
: never
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Infers prop type from component C
|
|
73
|
+
export type GetProps<C> =
|
|
74
|
+
C extends ComponentType<infer P>
|
|
75
|
+
? C extends ComponentClass<P>
|
|
76
|
+
? ClassAttributes<InstanceType<C>> & P
|
|
77
|
+
: P
|
|
78
|
+
: never
|
|
79
|
+
|
|
80
|
+
// Applies LibraryManagedAttributes (proper handling of defaultProps
|
|
81
|
+
// and propTypes).
|
|
82
|
+
export type GetLibraryManagedProps<C> = JSX.LibraryManagedAttributes<
|
|
83
|
+
C,
|
|
84
|
+
GetProps<C>
|
|
85
|
+
>
|
|
86
|
+
|
|
87
|
+
// Applies LibraryManagedAttributes (proper handling of defaultProps
|
|
88
|
+
// and propTypes), as well as defines WrappedComponent.
|
|
89
|
+
export type ConnectedComponent<
|
|
90
|
+
C extends ComponentType<any>,
|
|
91
|
+
P,
|
|
92
|
+
> = FunctionComponent<P> &
|
|
93
|
+
NonReactStatics<C> & {
|
|
94
|
+
WrappedComponent: C
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type ConnectPropsMaybeWithoutContext<TActualOwnProps> =
|
|
98
|
+
TActualOwnProps extends { context: any }
|
|
99
|
+
? Omit<ConnectProps, 'context'>
|
|
100
|
+
: ConnectProps
|
|
101
|
+
|
|
102
|
+
type Identity<T> = T
|
|
103
|
+
export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>
|
|
104
|
+
|
|
105
|
+
// Injects props and removes them from the prop requirements.
|
|
106
|
+
// Will not pass through the injected props if they are passed in during
|
|
107
|
+
// render. Also adds new prop requirements from TNeedsProps.
|
|
108
|
+
// Uses distributive omit to preserve discriminated unions part of original prop type.
|
|
109
|
+
// Note> Most of the time TNeedsProps is empty, because the overloads in `Connect`
|
|
110
|
+
// just pass in `{}`. The real props we need come from the component.
|
|
111
|
+
export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> = <
|
|
112
|
+
C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>,
|
|
113
|
+
>(
|
|
114
|
+
component: C,
|
|
115
|
+
) => ConnectedComponent<
|
|
116
|
+
C,
|
|
117
|
+
Mapped<
|
|
118
|
+
DistributiveOmit<
|
|
119
|
+
GetLibraryManagedProps<C>,
|
|
120
|
+
keyof Shared<TInjectedProps, GetLibraryManagedProps<C>>
|
|
121
|
+
> &
|
|
122
|
+
TNeedsProps &
|
|
123
|
+
ConnectPropsMaybeWithoutContext<TNeedsProps & GetProps<C>>
|
|
124
|
+
>
|
|
125
|
+
>
|
|
126
|
+
|
|
127
|
+
// Injects props and removes them from the prop requirements.
|
|
128
|
+
// Will not pass through the injected props if they are passed in during
|
|
129
|
+
// render.
|
|
130
|
+
export type InferableComponentEnhancer<TInjectedProps> =
|
|
131
|
+
InferableComponentEnhancerWithProps<TInjectedProps, {}>
|
|
132
|
+
|
|
133
|
+
export type InferThunkActionCreatorType<
|
|
134
|
+
TActionCreator extends (...args: any[]) => any,
|
|
135
|
+
> = TActionCreator extends (
|
|
136
|
+
...args: infer TParams
|
|
137
|
+
) => (...args: any[]) => infer TReturn
|
|
138
|
+
? (...args: TParams) => TReturn
|
|
139
|
+
: TActionCreator
|
|
140
|
+
|
|
141
|
+
export type HandleThunkActionCreator<TActionCreator> = TActionCreator extends (
|
|
142
|
+
...args: any[]
|
|
143
|
+
) => any
|
|
144
|
+
? InferThunkActionCreatorType<TActionCreator>
|
|
145
|
+
: TActionCreator
|
|
146
|
+
|
|
147
|
+
// redux-thunk middleware returns thunk's return value from dispatch call
|
|
148
|
+
// https://github.com/reduxjs/redux-thunk#composition
|
|
149
|
+
export type ResolveThunks<TDispatchProps> = TDispatchProps extends {
|
|
150
|
+
[key: string]: any
|
|
151
|
+
}
|
|
152
|
+
? {
|
|
153
|
+
[C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]>
|
|
154
|
+
}
|
|
155
|
+
: TDispatchProps
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* This interface allows you to easily create a hook that is properly typed for your
|
|
159
|
+
* store's root state.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
*
|
|
163
|
+
* interface RootState {
|
|
164
|
+
* property: string;
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
|
|
168
|
+
*/
|
|
169
|
+
export interface TypedUseSelectorHook<TState> {
|
|
170
|
+
<TSelected>(
|
|
171
|
+
selector: (state: TState) => TSelected,
|
|
172
|
+
equalityFn?: EqualityFn<NoInfer<TSelected>>,
|
|
173
|
+
): TSelected
|
|
174
|
+
<Selected = unknown>(
|
|
175
|
+
selector: (state: TState) => Selected,
|
|
176
|
+
options?: UseSelectorOptions<Selected>,
|
|
177
|
+
): Selected
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export type NoInfer<T> = [T][T extends any ? 0 : never]
|