Skip to content

Instantly share code, notes, and snippets.

@sergous
Last active May 24, 2024 02:21
Show Gist options
  • Save sergous/c3705b66b13c42323b4e5ab41085a41a to your computer and use it in GitHub Desktop.
Save sergous/c3705b66b13c42323b4e5ab41085a41a to your computer and use it in GitHub Desktop.
Zustand Redux-Like logger middleware
// Zustand Redux-Like logger middleware
//
// Based on https://github.com/itsramiel/zustand-logger-middleware and
// https://github.com/pmndrs/zustand/discussions/788#discussioncomment-7663573
//
// Require all store actions to be scoped in 'actions':
//
// const uiStoreCreator = (set, get) => {
// return {
// uiState: get()?.uiState || defaultUiState,
// actions: {
// setUiState: (uiState: UiState) =>
// set(
// produce((store: UiStore) => {
// store.uiState = { ...store.uiState, ...uiState }
// })
// ),
// },
// }
// }
import { StateCreator, StoreMutatorIdentifier } from "zustand"
type TLoggerFn = (set, get, api) => (actionName: string, args: unknown[]) => void
type TLogger = <
T extends object,
Mps extends [StoreMutatorIdentifier, unknown][] = [],
Mcs extends [StoreMutatorIdentifier, unknown][] = []
>(
f: StateCreator<T, Mps, Mcs>,
logger?: TLoggerFn
) => StateCreator<T, Mps, Mcs>
type TLoggerImpl = <T>(
storeInitializer: StateCreator<T, [], []>,
logger: TLoggerFn
) => StateCreator<T, [], []>
const isLogging = true
// Log every time state is changed
const zustandStoreLogger = (config) =>
zustandLoggerMiddleware(config, zustandConsoleLogger(isLogging))
const zustandConsoleLogger = (isLogging: boolean) => (set, get) => (actionName, actionArgs) => {
if (!isLogging) {
const { actions: prevActions, ["0"]: prevActionArgs, ...prevState } = get()
console.groupCollapsed(
`%cZustand ${actionName} @ ${new Date().toLocaleTimeString()}`,
"color: #8B0000; font-weight: bold;"
)
console.log("%cprev state", "color: #9E9E9E; font-weight: bold;", prevState)
console.log(`%caction ${actionName}`, "color: #03A9F4; font-weight: bold;", actionArgs[0])
set(actionArgs)
const { actions: nextActions, ["0"]: nextActionArgs, ...nextState } = get()
console.log("%cnext state", "color: #4CAF50; font-weight: bold;", nextState)
console.groupEnd()
} else {
set(args)
}
}
// Based on https://github.com/itsramiel/zustand-logger-middleware
zustandLoggerMiddleware: TLoggerImpl = (config, logger) => (set, get, api) => {
const originalConfig = config(set, get, api)
let actions = originalConfig["actions"]
if (actions && typeof actions === "object") {
const newActions = Object.fromEntries(
Object.entries(actions).map(([actionName, actionFn]) => {
let enhancedFn = actionFn
if (typeof actionFn === "function") {
enhancedFn = (...args: unknown[]) => {
const ret = actionFn(...args)
logger(set, get, api)(actionName, args)
return ret
}
}
return [actionName, enhancedFn]
})
)
// Spread originalConfig and overwrite the actions property
return { ...originalConfig, actions: newActions }
}
return originalConfig
}
export default zustandStoreLogger
@sergous
Copy link
Author

sergous commented Dec 29, 2023

Here is the console logging result:

Снимок экрана 2023-12-29 в 4 46 21 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment