Skip to content

Commit 33c53e0

Browse files
committed
refactor(utils): extract createReduxConnection
1 parent 9741fb2 commit 33c53e0

File tree

4 files changed

+67
-41
lines changed

4 files changed

+67
-41
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Message } from '../types';
2+
import { ReduxExtension } from './getReduxExtension';
3+
4+
// Original but incomplete type of the redux extension package
5+
type ConnectResponse = ReturnType<NonNullable<ReduxExtension>['connect']>;
6+
7+
export type Connection = {
8+
/** Mark the connection as not initiated, so it can be initiated before using it. */
9+
shouldInit?: boolean;
10+
11+
/** Initiate the connection and add it to the extension connections.
12+
* Should only be executed once in the live time of the connection.
13+
*/
14+
init: ConnectResponse['init'];
15+
16+
// FIXME https://github.com/reduxjs/redux-devtools/issues/1097
17+
/** Add a subscription to the connection.
18+
* The provided listener will be executed when the user interacts with the extension
19+
* with actions like time traveling, importing a state or the likes.
20+
*
21+
* @param listener function to be executed when an action is submitted
22+
* @returns function to unsubscribe the applied listener
23+
*/
24+
subscribe: (listener: (message: Message) => void) => (() => void) | undefined;
25+
26+
/** Send a new action to the connection to display the state change in the extension.
27+
* For example when the value of the store changes.
28+
*/
29+
send: ConnectResponse['send'];
30+
};
31+
32+
/** Wrapper for creating connections to the redux extension
33+
* Connections are used to display the stores value and value changes within the extension
34+
* as well as reacting to extension actions like time traveling.
35+
**/
36+
export const createReduxConnection = (
37+
extension: ReduxExtension | undefined,
38+
name: string,
39+
) => {
40+
if (!extension) return undefined;
41+
const connection = extension.connect({ name });
42+
43+
return Object.assign(connection, {
44+
shouldInit: true,
45+
}) as Connection;
46+
};

src/utils/redux-extension/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './getReduxExtension';
2+
export * from './createReduxConnection';

src/utils/useAtomDevtools.ts

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { useEffect, useRef } from 'react';
22
import { useAtom } from 'jotai/react';
33
import type { Atom, WritableAtom } from 'jotai/vanilla';
4-
import { getReduxExtension } from './redux-extension';
5-
import { Message } from './types';
4+
import {
5+
Connection,
6+
createReduxConnection,
7+
getReduxExtension,
8+
} from './redux-extension';
69

710
type DevtoolOptions = Parameters<typeof useAtom>[1] & {
811
name?: string;
@@ -21,13 +24,7 @@ export function useAtomDevtools<Value, Result>(
2124

2225
const lastValue = useRef(value);
2326
const isTimeTraveling = useRef(false);
24-
const devtools = useRef<
25-
ReturnType<
26-
NonNullable<typeof window['__REDUX_DEVTOOLS_EXTENSION__']>['connect']
27-
> & {
28-
shouldInit?: boolean;
29-
}
30-
>();
27+
const devtools = useRef<Connection>();
3128

3229
const atomName = name || anAtom.debugLabel || anAtom.toString();
3330

@@ -46,16 +43,9 @@ export function useAtomDevtools<Value, Result>(
4643
);
4744
};
4845

49-
devtools.current = extension.connect({ name: atomName });
46+
devtools.current = createReduxConnection(extension, atomName);
5047

51-
const unsubscribe = (
52-
devtools.current as unknown as {
53-
// FIXME https://github.com/reduxjs/redux-devtools/issues/1097
54-
subscribe: (
55-
listener: (message: Message) => void,
56-
) => (() => void) | undefined;
57-
}
58-
).subscribe((message) => {
48+
const unsubscribe = devtools.current?.subscribe((message) => {
5949
if (message.type === 'ACTION' && message.payload) {
6050
try {
6151
setValueIfWritable(JSON.parse(message.payload));
@@ -95,7 +85,7 @@ export function useAtomDevtools<Value, Result>(
9585
});
9686
}
9787
});
98-
devtools.current.shouldInit = true;
88+
9989
return unsubscribe;
10090
}, [anAtom, extension, atomName, setValue]);
10191

src/utils/useAtomsDevtools.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { useEffect, useRef } from 'react';
22
import { AnyAtom, AnyAtomValue, AtomsSnapshot, Options } from '../types';
3-
import { getReduxExtension } from './redux-extension';
4-
import { Message } from './types';
3+
import {
4+
Connection,
5+
createReduxConnection,
6+
getReduxExtension,
7+
} from './redux-extension';
58
import { useAtomsSnapshot } from './useAtomsSnapshot';
69
import { useGotoAtomsSnapshot } from './useGotoAtomsSnapshot';
710

@@ -41,13 +44,7 @@ export function useAtomsDevtools(
4144

4245
const isTimeTraveling = useRef(false);
4346
const isRecording = useRef(true);
44-
const devtools = useRef<
45-
ReturnType<
46-
NonNullable<typeof window['__REDUX_DEVTOOLS_EXTENSION__']>['connect']
47-
> & {
48-
shouldInit?: boolean;
49-
}
50-
>();
47+
const devtools = useRef<Connection>();
5148

5249
const snapshots = useRef<AtomsSnapshot[]>([]);
5350

@@ -63,16 +60,10 @@ export function useAtomsDevtools(
6360
}
6461
return snapshot;
6562
};
66-
const connection = extension.connect({ name });
67-
68-
const devtoolsUnsubscribe = (
69-
connection as unknown as {
70-
// FIXME https://github.com/reduxjs/redux-devtools/issues/1097
71-
subscribe: (
72-
listener: (message: Message) => void,
73-
) => (() => void) | undefined;
74-
}
75-
).subscribe((message) => {
63+
64+
devtools.current = createReduxConnection(extension, name);
65+
66+
const devtoolsUnsubscribe = devtools.current?.subscribe((message) => {
7667
switch (message.type) {
7768
case 'DISPATCH':
7869
switch (message.payload?.type) {
@@ -81,7 +72,7 @@ export function useAtomsDevtools(
8172
break;
8273

8374
case 'COMMIT':
84-
connection.init(getDevtoolsState(getSnapshotAt()));
75+
devtools.current?.init(getDevtoolsState(getSnapshotAt()));
8576
snapshots.current = [];
8677
break;
8778

@@ -98,8 +89,6 @@ export function useAtomsDevtools(
9889
}
9990
});
10091

101-
devtools.current = connection;
102-
devtools.current.shouldInit = true;
10392
return () => {
10493
extension?.disconnect?.();
10594
devtoolsUnsubscribe?.();

0 commit comments

Comments
 (0)