local Charm = require("./Charm") local React = require("./React") --[[ Returns a React state that updates when the getter function updates. Re-renders the component when the value changes. If the `dependencies` array is provided, a new effect is created for the current `getter` when the dependencies change. Otherwise, the effect is created only once, when the component is mounted. @param getter The signal or selector to watch. @param dependencies An array of values used to memoize the getter. @return The current state. ]] local function useSignalState(getter: () -> T, dependencies: { any }?): T local value, setValue = React.useState(getter) React.useLayoutEffect(function() return Charm.effect(function() -- Wrap in untracked to avoid tracking inner effect and atom calls Charm.untracked(setValue, getter()) end) end, dependencies or {}) return value end --[[ Returns a React binding that updates when the getter function updates. If the `dependencies` array is provided, a new effect is created for the current `getter` when the dependencies change. Otherwise, the effect is created only once, when the component is mounted. @param getter The atom or selector to watch. @param dependencies An array of values used to memoize the getter. @return A binding that stores the current state. ]] local function useSignalBinding(getter: () -> T, dependencies: { any }?) local initialValue = React.useMemo(getter, {}) local binding, setBinding = React.useBinding(initialValue) React.useLayoutEffect(function() return Charm.effect(function() -- Wrap in untracked to avoid tracking inner effect and atom calls Charm.untracked(setBinding, getter()) end) end, dependencies or {}) return binding end return { useSignalState = useSignalState, useSignalBinding = useSignalBinding, useAtom = useSignalState, }