@octanejs/redux-toolkit 0.1.0

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.
@@ -0,0 +1,2 @@
1
+ export const UNINITIALIZED_VALUE = Symbol();
2
+ export type UninitializedValue = typeof UNINITIALIZED_VALUE;
@@ -0,0 +1,38 @@
1
+ import { buildCreateApi, coreModule } from '@reduxjs/toolkit/query';
2
+ import { reactHooksModule, reactHooksModuleName } from './module';
3
+
4
+ export * from '@reduxjs/toolkit/query';
5
+ export { ApiProvider } from './ApiProvider.tsrx';
6
+
7
+ const createApi = /* @__PURE__ */ buildCreateApi(coreModule(), reactHooksModule());
8
+
9
+ export type {
10
+ TypedUseMutationResult,
11
+ TypedUseQueryHookResult,
12
+ TypedUseQueryStateResult,
13
+ TypedUseQuerySubscriptionResult,
14
+ TypedLazyQueryTrigger,
15
+ TypedUseLazyQuery,
16
+ TypedUseMutation,
17
+ TypedMutationTrigger,
18
+ TypedQueryStateSelector,
19
+ TypedUseQueryState,
20
+ TypedUseQuery,
21
+ TypedUseQuerySubscription,
22
+ TypedUseLazyQuerySubscription,
23
+ TypedUseQueryStateOptions,
24
+ TypedUseLazyQueryStateResult,
25
+ TypedUseInfiniteQuery,
26
+ TypedUseInfiniteQueryHookResult,
27
+ TypedUseInfiniteQueryStateResult,
28
+ TypedUseInfiniteQuerySubscriptionResult,
29
+ TypedUseInfiniteQueryStateOptions,
30
+ TypedInfiniteQueryStateSelector,
31
+ TypedUseInfiniteQuerySubscription,
32
+ TypedUseInfiniteQueryState,
33
+ TypedLazyInfiniteQueryTrigger,
34
+ TypedUseQuerySubscriptionOptions,
35
+ TypedUseMutationStateOptions,
36
+ } from './buildHooks';
37
+ export { UNINITIALIZED_VALUE } from './constants';
38
+ export { createApi, reactHooksModule, reactHooksModuleName };
@@ -0,0 +1,247 @@
1
+ import type {
2
+ Api,
3
+ BaseQueryFn,
4
+ EndpointDefinitions,
5
+ InfiniteQueryDefinition,
6
+ Module,
7
+ MutationDefinition,
8
+ PrefetchOptions,
9
+ QueryArgFrom,
10
+ QueryDefinition,
11
+ QueryKeys,
12
+ } from '@reduxjs/toolkit/query';
13
+ import {
14
+ batch as rrBatch,
15
+ useDispatch as rrUseDispatch,
16
+ useSelector as rrUseSelector,
17
+ useStore as rrUseStore,
18
+ } from '@octanejs/redux';
19
+ import type { CreateSelectorFunction } from 'reselect';
20
+ import { createSelector as _createSelector } from 'reselect';
21
+ import type { Dispatch, Store, UnknownAction } from 'redux';
22
+ import type { InfiniteQueryHooks, MutationHooks, QueryHooks } from './buildHooks';
23
+ import { buildHooks } from './buildHooks';
24
+ import type { HooksWithUniqueNames } from './namedHooks';
25
+
26
+ const isQueryDefinition = (definition: { type?: string }) => definition.type === 'query';
27
+ const isMutationDefinition = (definition: { type?: string }) => definition.type === 'mutation';
28
+ const isInfiniteQueryDefinition = (definition: { type?: string }) =>
29
+ definition.type === 'infinitequery';
30
+ const safeAssign = Object.assign;
31
+ const capitalize = (value: string) => value.charAt(0).toUpperCase() + value.slice(1);
32
+ const countObjectKeys = (value: object) => Object.keys(value).length;
33
+
34
+ export const reactHooksModuleName = /* @__PURE__ */ Symbol();
35
+ export type ReactHooksModule = typeof reactHooksModuleName;
36
+
37
+ declare module '@reduxjs/toolkit/query' {
38
+ export interface ApiModules<
39
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
40
+ BaseQuery extends BaseQueryFn,
41
+ Definitions extends EndpointDefinitions,
42
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
43
+ ReducerPath extends string,
44
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
45
+ TagTypes extends string,
46
+ > {
47
+ [reactHooksModuleName]: {
48
+ /**
49
+ * Endpoints based on the input endpoints provided to `createApi`, containing `select`, `hooks` and `action matchers`.
50
+ */
51
+ endpoints: {
52
+ [K in keyof Definitions]: Definitions[K] extends QueryDefinition<any, any, any, any, any>
53
+ ? QueryHooks<Definitions[K]>
54
+ : Definitions[K] extends MutationDefinition<any, any, any, any, any>
55
+ ? MutationHooks<Definitions[K]>
56
+ : Definitions[K] extends InfiniteQueryDefinition<any, any, any, any, any>
57
+ ? InfiniteQueryHooks<Definitions[K]>
58
+ : never;
59
+ };
60
+ /**
61
+ * A hook that accepts a string endpoint name, and provides a callback that when called, pre-fetches the data for that endpoint.
62
+ */
63
+ usePrefetch<EndpointName extends QueryKeys<Definitions>>(
64
+ endpointName: EndpointName,
65
+ options?: PrefetchOptions,
66
+ ): (arg: QueryArgFrom<Definitions[EndpointName]>, options?: PrefetchOptions) => void;
67
+ } & HooksWithUniqueNames<Definitions>;
68
+ }
69
+ }
70
+
71
+ type UseDispatch = () => Dispatch<UnknownAction>;
72
+ type UseSelector = <TState = unknown, Selected = unknown>(
73
+ selector: (state: TState) => Selected,
74
+ equalityFnOrOptions?: ((left: Selected, right: Selected) => boolean) | object,
75
+ ) => Selected;
76
+ type UseStore = () => Store<any>;
77
+
78
+ export interface ReactHooksModuleOptions {
79
+ /**
80
+ * The hooks from `@octanejs/redux` to be used
81
+ */
82
+ hooks?: {
83
+ /**
84
+ * The version of the `useDispatch` hook to be used
85
+ */
86
+ useDispatch: UseDispatch;
87
+ /**
88
+ * The version of the `useSelector` hook to be used
89
+ */
90
+ useSelector: UseSelector;
91
+ /**
92
+ * The version of the `useStore` hook to be used
93
+ */
94
+ useStore: UseStore;
95
+ };
96
+ /**
97
+ * The version of the `batchedUpdates` function to be used
98
+ */
99
+ batch?: (callback: () => void) => void;
100
+ /**
101
+ * Enables performing asynchronous tasks immediately within a render.
102
+ *
103
+ * @example
104
+ *
105
+ * ```ts
106
+ * import {
107
+ * buildCreateApi,
108
+ * coreModule,
109
+ * reactHooksModule
110
+ * } from '@octanejs/redux-toolkit/query/react'
111
+ *
112
+ * const createApi = buildCreateApi(
113
+ * coreModule(),
114
+ * reactHooksModule({ unstable__sideEffectsInRender: true })
115
+ * )
116
+ * ```
117
+ */
118
+ unstable__sideEffectsInRender?: boolean;
119
+ /**
120
+ * A selector creator (usually from `reselect`, or matching the same signature)
121
+ */
122
+ createSelector?: CreateSelectorFunction<any, any, any>;
123
+ }
124
+
125
+ /**
126
+ * Creates a module that generates Octane hooks from endpoints, for use with `buildCreateApi`.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * const MyContext = createContext<ReactReduxContextValue | null>(null);
131
+ * const customCreateApi = buildCreateApi(
132
+ * coreModule(),
133
+ * reactHooksModule({
134
+ * hooks: {
135
+ * useDispatch: createDispatchHook(MyContext),
136
+ * useSelector: createSelectorHook(MyContext),
137
+ * useStore: createStoreHook(MyContext)
138
+ * }
139
+ * })
140
+ * );
141
+ * ```
142
+ *
143
+ * @returns A module for use with `buildCreateApi`
144
+ */
145
+ export const reactHooksModule = ({
146
+ batch = rrBatch,
147
+ hooks = {
148
+ useDispatch: rrUseDispatch as UseDispatch,
149
+ useSelector: rrUseSelector as UseSelector,
150
+ useStore: rrUseStore as UseStore,
151
+ },
152
+ createSelector = _createSelector,
153
+ unstable__sideEffectsInRender = false,
154
+ ...rest
155
+ }: ReactHooksModuleOptions = {}): Module<ReactHooksModule> => {
156
+ if (process.env.NODE_ENV !== 'production') {
157
+ const hookNames = ['useDispatch', 'useSelector', 'useStore'] as const;
158
+ let warned = false;
159
+ for (const hookName of hookNames) {
160
+ // warn for old hook options
161
+ if (countObjectKeys(rest) > 0) {
162
+ if ((rest as Partial<typeof hooks>)[hookName]) {
163
+ if (!warned) {
164
+ console.warn(
165
+ 'As of RTK 2.0, the hooks now need to be specified as one object, provided under a `hooks` key:' +
166
+ '\n`reactHooksModule({ hooks: { useDispatch, useSelector, useStore } })`',
167
+ );
168
+ warned = true;
169
+ }
170
+ }
171
+ // migrate
172
+ // @ts-ignore
173
+ hooks[hookName] = rest[hookName];
174
+ }
175
+ // then make sure we have them all
176
+ if (typeof hooks[hookName] !== 'function') {
177
+ throw new Error(
178
+ `When using custom hooks for context, all ${
179
+ hookNames.length
180
+ } hooks need to be provided: ${hookNames.join(
181
+ ', ',
182
+ )}.\nHook ${hookName} was either not provided or not a function.`,
183
+ );
184
+ }
185
+ }
186
+ }
187
+
188
+ return {
189
+ name: reactHooksModuleName,
190
+ init(api, { serializeQueryArgs }, context) {
191
+ const anyApi = api as any as Api<any, Record<string, any>, any, any, ReactHooksModule>;
192
+ const { buildQueryHooks, buildInfiniteQueryHooks, buildMutationHook, usePrefetch } =
193
+ buildHooks({
194
+ api,
195
+ moduleOptions: {
196
+ batch,
197
+ hooks,
198
+ unstable__sideEffectsInRender,
199
+ createSelector,
200
+ },
201
+ serializeQueryArgs,
202
+ context,
203
+ });
204
+ safeAssign(anyApi, { usePrefetch });
205
+ safeAssign(context, { batch });
206
+
207
+ return {
208
+ injectEndpoint(endpointName, definition) {
209
+ if (isQueryDefinition(definition)) {
210
+ const {
211
+ useQuery,
212
+ useLazyQuery,
213
+ useLazyQuerySubscription,
214
+ useQueryState,
215
+ useQuerySubscription,
216
+ } = buildQueryHooks(endpointName);
217
+ safeAssign(anyApi.endpoints[endpointName], {
218
+ useQuery,
219
+ useLazyQuery,
220
+ useLazyQuerySubscription,
221
+ useQueryState,
222
+ useQuerySubscription,
223
+ });
224
+ (api as any)[`use${capitalize(endpointName)}Query`] = useQuery;
225
+ (api as any)[`useLazy${capitalize(endpointName)}Query`] = useLazyQuery;
226
+ }
227
+ if (isMutationDefinition(definition)) {
228
+ const useMutation = buildMutationHook(endpointName);
229
+ safeAssign(anyApi.endpoints[endpointName], {
230
+ useMutation,
231
+ });
232
+ (api as any)[`use${capitalize(endpointName)}Mutation`] = useMutation;
233
+ } else if (isInfiniteQueryDefinition(definition)) {
234
+ const { useInfiniteQuery, useInfiniteQuerySubscription, useInfiniteQueryState } =
235
+ buildInfiniteQueryHooks(endpointName);
236
+ safeAssign(anyApi.endpoints[endpointName], {
237
+ useInfiniteQuery,
238
+ useInfiniteQuerySubscription,
239
+ useInfiniteQueryState,
240
+ });
241
+ (api as any)[`use${capitalize(endpointName)}InfiniteQuery`] = useInfiniteQuery;
242
+ }
243
+ },
244
+ };
245
+ },
246
+ };
247
+ };
@@ -0,0 +1,48 @@
1
+ import type {
2
+ DefinitionType,
3
+ EndpointDefinitions,
4
+ MutationDefinition,
5
+ QueryDefinition,
6
+ InfiniteQueryDefinition,
7
+ } from '@reduxjs/toolkit/query';
8
+ import type { UseInfiniteQuery, UseLazyQuery, UseMutation, UseQuery } from './buildHooks';
9
+
10
+ type QueryHookNames<Definitions extends EndpointDefinitions> = {
11
+ [K in keyof Definitions as Definitions[K] extends {
12
+ type: DefinitionType.query;
13
+ }
14
+ ? `use${Capitalize<K & string>}Query`
15
+ : never]: UseQuery<Extract<Definitions[K], QueryDefinition<any, any, any, any>>>;
16
+ };
17
+
18
+ type LazyQueryHookNames<Definitions extends EndpointDefinitions> = {
19
+ [K in keyof Definitions as Definitions[K] extends {
20
+ type: DefinitionType.query;
21
+ }
22
+ ? `useLazy${Capitalize<K & string>}Query`
23
+ : never]: UseLazyQuery<Extract<Definitions[K], QueryDefinition<any, any, any, any>>>;
24
+ };
25
+
26
+ type InfiniteQueryHookNames<Definitions extends EndpointDefinitions> = {
27
+ [K in keyof Definitions as Definitions[K] extends {
28
+ type: DefinitionType.infinitequery;
29
+ }
30
+ ? `use${Capitalize<K & string>}InfiniteQuery`
31
+ : never]: UseInfiniteQuery<
32
+ Extract<Definitions[K], InfiniteQueryDefinition<any, any, any, any, any>>
33
+ >;
34
+ };
35
+
36
+ type MutationHookNames<Definitions extends EndpointDefinitions> = {
37
+ [K in keyof Definitions as Definitions[K] extends {
38
+ type: DefinitionType.mutation;
39
+ }
40
+ ? `use${Capitalize<K & string>}Mutation`
41
+ : never]: UseMutation<Extract<Definitions[K], MutationDefinition<any, any, any, any>>>;
42
+ };
43
+
44
+ export type HooksWithUniqueNames<Definitions extends EndpointDefinitions> =
45
+ QueryHookNames<Definitions> &
46
+ LazyQueryHookNames<Definitions> &
47
+ InfiniteQueryHookNames<Definitions> &
48
+ MutationHookNames<Definitions>;
@@ -0,0 +1,14 @@
1
+ import { useEffect, useRef, useMemo } from 'octane';
2
+ import { copyWithStructuralSharing } from '@reduxjs/toolkit/query';
3
+
4
+ export function useStableQueryArgs<T>(queryArgs: T) {
5
+ const cache = useRef(queryArgs);
6
+ const copy = useMemo(() => copyWithStructuralSharing(cache.current, queryArgs), [queryArgs]);
7
+ useEffect(() => {
8
+ if (cache.current !== copy) {
9
+ cache.current = copy;
10
+ }
11
+ }, [copy]);
12
+
13
+ return copy;
14
+ }
@@ -0,0 +1,13 @@
1
+ import { useEffect, useRef } from 'octane';
2
+ import { shallowEqual } from '@octanejs/redux';
3
+
4
+ export function useShallowStableValue<T>(value: T) {
5
+ const cache = useRef(value);
6
+ useEffect(() => {
7
+ if (!shallowEqual(cache.current, value)) {
8
+ cache.current = value;
9
+ }
10
+ }, [value]);
11
+
12
+ return shallowEqual(cache.current, value) ? cache.current : value;
13
+ }
@@ -0,0 +1,5 @@
1
+ // Compatibility counterpart of `@reduxjs/toolkit/react`: the root Toolkit
2
+ // surface plus the dynamic-middleware helper bound to @octanejs/redux.
3
+ export * from '@reduxjs/toolkit';
4
+ export { createDynamicMiddleware } from '../dynamicMiddleware/react';
5
+ export type { CreateDispatchWithMiddlewareHook } from '../dynamicMiddleware/react';