-- Compiled with roblox-ts v1.3.2 local TS = _G[script] local useStore = TS.import(script, script.Parent, "use-store").default --[[ * * This interface allows you to easily create a hook that is properly typed for your store's root state. * * @example * interface RootState { * property: string; * } * * const useAppSelector: ITypedUseSelectorHook = useSelector; ]] --[[ * * A hook to access the Rodux Store's state. This hook takes a selector function as an argument. The selector is called * with the store state. * * This hook takes an optional equality comparison function as the second parameter that allows you to customize the * way the selected state is compared to determine whether the component needs to be re-rendered. * * @param selector - The selector function * @param equalityFn - The function that will be used to determine equality * * @returns The selected portion of the state ]] local useSelector = function(hooks, selector, equalityFn) if equalityFn == nil then equalityFn = function(a, b) return a == b end end local _, forceRender = hooks.useReducer(function(s) return s + 1 end, 0) local store = useStore(hooks) local latestSubscriptionCallbackError = hooks.useValue() local latestSelector = hooks.useValue() local latestStoreState = hooks.useValue() local latestSelectedState = hooks.useValue() local storeState = store:getState() local selectedState TS.try(function() local _value = selector ~= latestSelector.value or (storeState ~= latestStoreState.value or latestSubscriptionCallbackError.value) if _value ~= "" and _value then local newSelectedState = selector(storeState) -- ensure latest selected state is reused so that a custom equality function can result in identical references if latestSelectedState.value == nil or not equalityFn(newSelectedState, latestSelectedState.value) then selectedState = newSelectedState else selectedState = latestSelectedState.value end else selectedState = latestSelectedState.value end end, function(err) if latestSubscriptionCallbackError.value ~= nil then err ..= "\nThe error may be correlated with this previous error:\n" .. (latestSubscriptionCallbackError.value .. "\n\n") end error(err) end) hooks.useEffect(function() latestSelector.value = selector latestStoreState.value = storeState latestSelectedState.value = selectedState latestSubscriptionCallbackError.value = nil end) hooks.useEffect(function() local checkForUpdates = function(newStoreState) local _exitType, _returns = TS.try(function() -- Avoid calling selector multiple times if the store's state has not changed if newStoreState == latestStoreState.value then return TS.TRY_RETURN, {} end local newSelectedState = latestSelector.value(newStoreState) if equalityFn(newSelectedState, latestSelectedState.value) then return TS.TRY_RETURN, {} end latestSelectedState.value = newSelectedState latestStoreState.value = newStoreState end, function(err) -- we ignore all errors here, since when the component -- is re-rendered, the selectors are called again, and -- will throw again, if neither props nor store state -- changed latestSubscriptionCallbackError.value = err end) if _exitType then return unpack(_returns) end task.spawn(forceRender) end local subscription = store.changed:connect(checkForUpdates) checkForUpdates(store:getState()) return function() return subscription:disconnect() end end, { store }) return selectedState end local default = useSelector return { useSelector = useSelector, default = default, }