Last active
September 15, 2024 22:15
-
-
Save cxmeel/7d32407f187abd40c945aa6625585d15 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type Value<T> = | |
((value: (T | (current: T) -> T)?, bypassSignals: boolean?) -> T) | |
& { | |
changed: RBXScriptSignal<T, T>, | |
initialValue: T, | |
destroy: () -> (), | |
reset: () -> (), | |
onChange: (callback: (prev: T, next: T) -> (), runOnInit: boolean?) -> (), | |
onReset: (() -> ())?, | |
} | |
local function Value<T>( | |
value: T, | |
api: { | |
validate: ((value: T) -> boolean)?, | |
}? | |
) | |
local changedSignal = Instance.new("BindableEvent") | |
local cachedValue = value | |
local proxy: any | |
proxy = setmetatable({ | |
changed = changedSignal.Event, | |
initialValue = value, | |
onChange = function(_, callback, runOnInit) | |
local connection = changedSignal.Event:Connect(function(...) | |
callback(...) | |
end) | |
if runOnInit then | |
callback(value, value) | |
end | |
return function() | |
connection:Disconnect() | |
end | |
end, | |
destroy = function() | |
changedSignal:Destroy() | |
changedSignal = nil :: never | |
cachedValue = nil :: never | |
end, | |
reset = function() | |
local currentValue = cachedValue | |
cachedValue = value | |
changedSignal:Fire(currentValue, value) | |
if proxy.onReset then | |
proxy.onReset() | |
end | |
end, | |
onReset = nil :: () -> ()?, | |
}, { | |
__call = function(_, ...) | |
if select("#", ...) == 0 then | |
return cachedValue | |
end | |
local proposedValue = select(1, ...) | |
if typeof(proposedValue) == "function" then | |
proposedValue = proposedValue(cachedValue) | |
end | |
if cachedValue == proposedValue then | |
return cachedValue | |
end | |
if api and api.validate and not api.validate(proposedValue) then | |
return cachedValue | |
end | |
if select(2, ...) ~= false then | |
changedSignal:Fire(cachedValue, proposedValue) | |
end | |
cachedValue = proposedValue | |
return proposedValue | |
end, | |
}) | |
return proxy :: Value<T> | |
end | |
return Value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local React = require("@pkgs/React") | |
local useEffect = React.useEffect | |
local useState = React.useState | |
local function useValue<T, V>(value: Value<T>): T | |
local currentValue, setCurrentValue = useState(value()) | |
useEffect(function() | |
local valueChanged = value.changed:Connect(function(_, newValue) | |
setCurrentValue(function(current) | |
if current ~= newValue then | |
return newValue | |
end | |
return current | |
end) | |
end) | |
return function() | |
valueChanged:Disconnect() | |
end | |
end, { value.changed } :: { any }) | |
return currentValue | |
end | |
return useValue |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment