add gs
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
local RunService = game:GetService("RunService")
|
||||
|
||||
local Signal = require(script.Parent.Signal)
|
||||
local NoYield = require(script.Parent.NoYield)
|
||||
|
||||
local Store = {}
|
||||
|
||||
-- This value is exposed as a private value so that the test code can stay in
|
||||
-- sync with what event we listen to for dispatching the Changed event.
|
||||
-- It may not be Heartbeat in the future.
|
||||
Store._flushEvent = RunService.Heartbeat
|
||||
|
||||
Store.__index = Store
|
||||
|
||||
--[[
|
||||
Create a new Store whose state is transformed by the given reducer function.
|
||||
|
||||
Each time an action is dispatched to the store, the new state of the store
|
||||
is given by:
|
||||
|
||||
state = reducer(state, action)
|
||||
|
||||
Reducers do not mutate the state object, so the original state is still
|
||||
valid.
|
||||
]]
|
||||
function Store.new(reducer, initialState, middlewares)
|
||||
assert(typeof(reducer) == "function", "Bad argument #1 to Store.new, expected function.")
|
||||
assert(middlewares == nil or typeof(middlewares) == "table", "Bad argument #3 to Store.new, expected nil or table.")
|
||||
|
||||
local self = {}
|
||||
|
||||
self._reducer = reducer
|
||||
self._state = reducer(initialState, {
|
||||
type = "@@INIT",
|
||||
})
|
||||
self._lastState = self._state
|
||||
|
||||
self._mutatedSinceFlush = false
|
||||
self._connections = {}
|
||||
|
||||
self.changed = Signal.new()
|
||||
|
||||
setmetatable(self, Store)
|
||||
|
||||
local connection = self._flushEvent:Connect(function()
|
||||
self:flush()
|
||||
end)
|
||||
table.insert(self._connections, connection)
|
||||
|
||||
if middlewares then
|
||||
local unboundDispatch = self.dispatch
|
||||
local dispatch = function(...)
|
||||
return unboundDispatch(self, ...)
|
||||
end
|
||||
|
||||
for i = #middlewares, 1, -1 do
|
||||
local middleware = middlewares[i]
|
||||
dispatch = middleware(dispatch, self)
|
||||
end
|
||||
|
||||
self.dispatch = function(self, ...)
|
||||
return dispatch(...)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[
|
||||
Get the current state of the Store. Do not mutate this!
|
||||
]]
|
||||
function Store:getState()
|
||||
return self._state
|
||||
end
|
||||
|
||||
--[[
|
||||
Dispatch an action to the store. This allows the store's reducer to mutate
|
||||
the state of the application by creating a new copy of the state.
|
||||
|
||||
Listeners on the changed event of the store are notified when the state
|
||||
changes, but not necessarily on every Dispatch.
|
||||
]]
|
||||
function Store:dispatch(action)
|
||||
if typeof(action) == "table" then
|
||||
if action.type == nil then
|
||||
error("action does not have a type field", 2)
|
||||
end
|
||||
|
||||
self._state = self._reducer(self._state, action)
|
||||
self._mutatedSinceFlush = true
|
||||
else
|
||||
error(("actions of type %q are not permitted"):format(typeof(action)), 2)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Marks the store as deleted, disconnecting any outstanding connections.
|
||||
]]
|
||||
function Store:destruct()
|
||||
for _, connection in ipairs(self._connections) do
|
||||
connection:Disconnect()
|
||||
end
|
||||
|
||||
self._connections = nil
|
||||
end
|
||||
|
||||
--[[
|
||||
Flush all pending actions since the last change event was dispatched.
|
||||
]]
|
||||
function Store:flush()
|
||||
if not self._mutatedSinceFlush then
|
||||
return
|
||||
end
|
||||
|
||||
self._mutatedSinceFlush = false
|
||||
|
||||
-- On self.changed:fire(), further actions may be immediately dispatched, in
|
||||
-- which case self._lastState will be set to the most recent self._state,
|
||||
-- unless we cache this value first
|
||||
local state = self._state
|
||||
|
||||
-- If a changed listener yields, *very* surprising bugs can ensue.
|
||||
-- Because of that, changed listeners cannot yield.
|
||||
NoYield(function()
|
||||
self.changed:fire(state, self._lastState)
|
||||
end)
|
||||
|
||||
self._lastState = state
|
||||
end
|
||||
|
||||
return Store
|
||||
Reference in New Issue
Block a user