Devtools
The fifth argument to Store.new takes a devtools object that you can optionally provide. A devtools object has only two requirements: devtools.__className must be "Devtools" and devtools:_hookIntoStore(store) must be a valid function call. Beyond that, your devtools can be anything you need it to be.
Devtools can be very useful during development in gathering performance data, providing introspection, debugging, etc. We leave the devtools implementation up to the user in order to support any and all use cases, such as store modification in unit testing, live state inspection plugins, and whatever else you come up with.
A simple example of a devtools that profiles and logs:
local Devtools = {}
Devtools.__className = "Devtools"
Devtools.__index = Devtools
-- Creates a new Devtools object
function Devtools.new()
local self = setmetatable({
_events = table.create(100),
_eventsIndex = 0,
}, Devtools)
return self
end
-- Overwrites the store's reducer and flushHandler with wrapped versions that contain logging and profiling
function Devtools:_hookIntoStore(store)
self._store = store
self._source = store._source
self._originalReducer = store._reducer
store._reducer = function(state: any, action: any): any
local startClock = os.clock()
local result = self._originalReducer(state, action)
local stopClock = os.clock()
self:_addEvent("Reduce", {
name = action.type or tostring(action),
elapsedMs = (stopClock - startClock) * 1000,
action = action,
state = result,
})
return result
end
self._originalFlushHandler = store._flushHandler
store._flushHandler = function(...)
local startClock = os.clock()
self._originalFlushHandler(...)
local stopClock = os.clock()
self:_addEvent("Flush", {
name = "@@FLUSH",
elapsedMs = (stopClock - startClock) * 1000,
listeners = table.clone(store.changed._listeners),
})
end
end
-- Adds an event to the log
-- Automatically adds event.timestamp and event.source
function Devtools:_addEvent(eventType: "Reduce" | "Flush", props: { [any]: any })
self._eventsIndex = (self._eventsIndex or 0) + 1
self._events[self._eventsIndex] = {
eventType = eventType,
source = self._source,
timestamp = DateTime.now().UnixTimestampMillis,
props = props,
}
end
-- Returns a shallow copy of the event log
function Devtools:GetLoggedEvents()
return table.clone(self._events)
end