Files
react-navigation/packages/core/src/useDevTools.tsx
2019-09-28 11:58:21 +02:00

101 lines
2.3 KiB
TypeScript

import * as React from 'react';
import { NavigationState, NavigationAction, PartialState } from './types';
type State = NavigationState | PartialState<NavigationState> | undefined;
type Options = {
name: string;
reset: (state: NavigationState) => void;
state: State;
};
type DevTools = {
init(value: any): void;
send(action: any, value: any): void;
subscribe(
listener: (message: { type: string; [key: string]: any }) => void
): () => void;
};
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace NodeJS {
interface Global {
__REDUX_DEVTOOLS_EXTENSION__:
| {
connect(options: { name: string }): DevTools;
disconnect(): void;
}
| undefined;
}
}
}
export default function useDevTools({ name, reset, state }: Options) {
const devToolsRef = React.useRef<DevTools>();
if (
process.env.NODE_ENV !== 'production' &&
global.__REDUX_DEVTOOLS_EXTENSION__ &&
devToolsRef.current === undefined
) {
devToolsRef.current = global.__REDUX_DEVTOOLS_EXTENSION__.connect({ name });
}
const devTools = devToolsRef.current;
const lastStateRef = React.useRef<State>(state);
const actions = React.useRef<Array<NavigationAction | string>>([]);
React.useEffect(() => {
devTools && devTools.init(lastStateRef.current);
}, [devTools]);
React.useEffect(
() =>
devTools &&
devTools.subscribe(message => {
if (message.type === 'DISPATCH' && message.state) {
reset(JSON.parse(message.state));
}
}),
[devTools, reset]
);
const trackState = React.useCallback(
(state: State) => {
if (!devTools) {
return;
}
while (actions.current.length > 1) {
devTools.send(actions.current.shift(), lastStateRef.current);
}
if (actions.current.length) {
devTools.send(actions.current.pop(), state);
} else if (lastStateRef.current !== state) {
devTools.send('@@UNKNOWN', state);
}
lastStateRef.current = state;
},
[devTools]
);
const trackAction = React.useCallback(
(action: NavigationAction | string) => {
if (!devTools) {
return;
}
actions.current.push(action);
},
[devTools]
);
return {
trackAction,
trackState,
};
}