Skip to content

Commit

Permalink
Make table form of mapDispatchToProps work with callable table action…
Browse files Browse the repository at this point in the history
…Creators
  • Loading branch information
tonycuadra committed Oct 8, 2024
1 parent 5be1d9e commit 26e2bc8
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 8 deletions.
24 changes: 16 additions & 8 deletions src/connect.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ local function noop()
return nil
end

--[[
Returns `true` if the value can be called i.e. you can write `value(...)`.
]]
local function isCallable(value: any): boolean
return type(value) == "function" or
(type(value) == "table" and getmetatable(value) and getmetatable(value).__call ~= nil) or false
end

--[[
The stateUpdater accepts props when they update and computes the
complete set of props that should be passed to the wrapped component.
Expand Down Expand Up @@ -77,7 +85,7 @@ local function connect<StoreState, Props, MappedStatePartialProps, MappedDispatc
>?
)
if mapStateToPropsOrThunk ~= nil then
assert(typeof(mapStateToPropsOrThunk) == "function", "mapStateToProps must be a function or nil!")
assert(isCallable(mapStateToPropsOrThunk), "mapStateToProps must be a function or nil!")
else
mapStateToPropsOrThunk = noop
end
Expand Down Expand Up @@ -142,7 +150,7 @@ local function connect<StoreState, Props, MappedStatePartialProps, MappedDispatc
-- value. In this variant, we keep that value as mapStateToProps
-- instead of the original mapStateToProps. This matches react-redux
-- and enables connectors to keep instance-level state.
if typeof(mappedStoreState) == "function" then
if isCallable(mappedStoreState) then
mapStateToProps = mappedStoreState
mappedStoreState = mapStateToProps(storeState, self.props.innerProps)
end
Expand All @@ -164,20 +172,20 @@ local function connect<StoreState, Props, MappedStatePartialProps, MappedDispatc
end

local mappedStoreDispatch: any
if mapDispatchType == "table" then
if isCallable(mapDispatchToProps) then
mappedStoreDispatch = (mapDispatchToProps :: MapDispatchToProps<StoreState, MappedDispatchPartialProps>)(
(dispatch :: any) :: ThunkfulDispatchProp<StoreState>
)
elseif mapDispatchType == "table" then
mappedStoreDispatch = {}

for key, actionCreator in pairs(mapDispatchToProps :: ActionCreatorMap) do
assert(typeof(actionCreator) == "function", "mapDispatchToProps must contain function values")
assert(isCallable(actionCreator), "mapDispatchToProps must contain function values")

mappedStoreDispatch[key] = function(...)
dispatch(actionCreator(...))
end
end
elseif mapDispatchType == "function" then
mappedStoreDispatch = (mapDispatchToProps :: MapDispatchToProps<StoreState, MappedDispatchPartialProps>)(
(dispatch :: any) :: ThunkfulDispatchProp<StoreState>
)
end

local stateUpdater = makeStateUpdater(self.store)
Expand Down
6 changes: 6 additions & 0 deletions src/connect.spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ return function()
})
end)

it("should accept action creators that are callable tables", function()
connect(nil, {
foo = Rodux.makeActionCreator("Foo", function() end),
})
end)

it("should throw if not passed a component", function()
local selector = function(store)
return {}
Expand Down

0 comments on commit 26e2bc8

Please sign in to comment.