Simple “selector” library for Rodux
npm install @rbxts/roselect---


`` local function shopItemsSelector(state) local function taxPercentSelector(state) local subtotalSelector = createSelector( local taxSelector = createSelector( local totalSelector = createSelector( local exampleState = { print(subtotalSelector(exampleState)) -- 2.15 ` interface State { const shopItemsSelector = (state: State) => state.shop.items; const subtotalSelector = createSelector( const taxSelector = createSelector( export const totalSelector = createSelector( const exampleState = identity print(subtotalSelector(exampleState)); // 2.15luau
lua
local roselect = require(path.to.roselect)
local createSelector = roselect.createSelector
local reduce = roselect.reduce
return state.shop.items
end
return state.shop.taxPercent
end
shopItemsSelector,
function(items)
return reduce(items, function(acc, item)
return acc + item.value
end, 0)
end
)
subtotalSelector,
taxPercentSelector,
function(subtotal, taxPercent)
return subtotal * (taxPercent / 100)
end
)
subtotalSelector,
taxSelector,
function(subtotal, tax)
return { total = subtotal + tax }
end
)
shop = {
taxPercent = 8,
items = {
{ name = "apple", value = 1.20 },
{ name = "orange", value = 0.95 }
}
}
}
print(taxSelector(exampleState)) -- 0.172
print(totalSelector(exampleState)) -- { total = 2.322 }
`roblox-ts
ts
import { createSelector } from "@rbxts/roselect";
shop: {
taxPercent: number;
items: { name: string; value: number; }[];
}
}
const taxPercentSelector = (state: State) => state.shop.taxPercent;
shopItemsSelector,
items => items.reduce((acc, item) => acc + item.value, 0)
);
subtotalSelector,
taxPercentSelector,
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
);
subtotalSelector,
taxSelector,
(subtotal, tax) => ({ total: subtotal + tax })
);
shop: {
taxPercent: 8,
items: [
{ name: 'apple', value: 1.20 },
{ name: 'orange', value: 0.95 },
]
}
});
print(taxSelector(exampleState)); // 0.172
print(totalSelector(exampleState)); // { total: 2.322 }
`
bash
git clone https://github.com/HylianBasement/roselect.git ./modules
`$3
The installation can be done via npm i @rbxts/roselect.Composing Selectors
It's important to mention that createSelector checks if the first parameter is an array of dependencies.
Since lua tables are both dictionary and list, it treats that parameter as an array of selectors that needs to be composed.
A memoized selector can itself be an input-selector to another memoized selector. Here is getVisibleTodos being used as an input-selector to a selector that further filters the todos by keyword:
luau
`lua
local function getVisibilityFilter(state)
return state.visibilityFilter
endlocal function getTodos(state)
return state.todos
end
local function getKeyword(state)
return state.keyword
end
local getVisibleTodos = createSelector(
{ getVisibilityFilter, getTodos },
function(visibilityFilter, todos)
if visibilityFilter == "SHOW_ALL" then
return todos
elseif visibilityFilter == "SHOW_COMPLETED" then
local newTodos = {}
for k, todo in pairs(todos) do
if todo.completed then
newTodos[k] = todo
end
end
return newTodos
elseif visibilityFilter == "SHOW_ACTIVE" then
local newTodos = {}
for k, todo in pairs(todos) do
if not todo.completed then
newTodos[k] = todo
end
end
return newTodos
end
end
)
local getVisibleTodosFilteredByKeyword = createSelector(
{ getVisibleTodos, getKeyword },
function(visibleTodos, keyword)
local newTodos = {}
for k, todo in pairs(visibleTodos) do
if todo.text:find(keyword) then
newTodos[k] = todo
end
end
return newTodos
end
)
return {
getVisibleTodos = getVisibleTodos
}
`roblox-ts
`ts
const getVisibilityFilter = (state: State) => state.visibilityFilter;
const getTodos = (state: State) => state.todos;
const getKeyword = (state: State) => state.keyword;
export const getVisibleTodos = createSelector(
[ getVisibilityFilter, getTodos ],
(visibilityFilter, todos) => {
switch (visibilityFilter) {
case "SHOW_ALL":
return todos;
case "SHOW_COMPLETED":
return todos.filter(t => t.completed);
case "SHOW_ACTIVE":
return todos.filter(t => !t.completed);
}
}
);const getVisibleTodosFilteredByKeyword = createSelector(
[ getVisibleTodos, getKeyword ],
(visibleTodos, keyword) => visibleTodos.filter(
todo => todo.text.includes(keyword)
)
);
``