Roblox/rodux

Add Rodux.createAction

Closed this issue · 4 comments

We should introduce a more standardized way of creating and using Rodux actions to prevent common errors and more closely associate actions with the reducers that handle them. A file defining an action would look like this:

-- necessary requires to include Rodux

return Rodux.createAction(script.name, function(value)
	return {
		value = value,
	}
end)

Dispatching that action would look like this:

local MyAction = require(Actions.MyAction)

-- ...

store:Dispatch(MyAction(value))

A reducer that handles this action would look like this:

local MyAction = require(Actions.MyAction)

-- ...

if action.type == MyAction.name then
	-- change some state!
end

We should model Rodux.createAction off of the following Action.lua implementation:

return function(name, fn)
	assert(type(name) == "string", "A name must be provided to create an Action")
	assert(type(fn) == "function", "A function must be provided to create an Action")

	return setmetatable({
		name = name,
	}, {
		__call = function(self, ...)
			local result = fn(...)

			assert(type(result) == "table", "An action must return a table")

			result.type = name

			return result
		end
	})
end

I kind of like the fact that this proposal

  • Mirrors Rodux.createReducer
  • Does not affect users' ability to use actions normally

Having a formal pattern for this at least as an option might be nice. Action is a thing I copy into a lot of projects in order to use it specifically with Rodux.

I also often like to add something like this to the __call function in the sample implementation that @SlartibartfastFjords provided:

setmetatable(result, {
   __index = function(table, key)
      error("Attempted to access nonexistent key " .. tostring(key) .. " on action " .. name, 2)
   end
})

That way if I ever make typos in reducers I'll find it right away instead of quietly setting things to nil.

We have to be careful with trying to define when table indexes are mistakes, since Lua doesn't differentiate between a value in a table being nil and it being an invalid key!

Right, I agree. I find it useful for my cases, but it's too presumptive to put in a common version. I think having one at all would be nice though.

I'd like to bring this issue up again. I think since this helper is used as the standard way to create actions across so many different projects it seems sufficiently useful to add to the core Rodux API. This would stop this action helper being duplicated in so many different places. Alternatively we could make a separate action helper package but I think this will be harder to discover than something in the Rodux API.