Skip to content

ForKeys

ForKeys is a state object that processes keys from another table.

It supports both constants and state objects.

local data = {Red = "foo", Blue = "bar"}
local prefix = scope:Value("Key_")

local renamed = scope:ForKeys(data, function(use, scope, key)
    return use(prefix) .. key
end)

print(peek(renamed)) --> {Key_Red = "foo", Key_Blue = "bar"}

prefix:set("colour")
print(peek(renamed)) --> {colourRed = "foo", colourBlue = "bar"}

Usage

To create a new ForKeys object, call the constructor with an input table and a processor function. The first two arguments are use and scope, just like computed objects. The third argument is one of the keys read from the input table.

local data = {red = "foo", blue = "bar"}
local renamed = scope:ForKeys(data, function(use, scope, key)
    return string.upper(key)
end)

You can read the table of processed keys using peek():

local data = {red = "foo", blue = "bar"}
local renamed = scope:ForKeys(data, function(use, scope, key)
    return string.upper(key)
end)

print(peek(renamed)) --> {RED = "foo", BLUE = "bar"}

The input table can be a state object. When the input table changes, the output will update.

local foodSet = scope:Value({})

local prefixes = { pie = "tasty", chocolate = "yummy", broccoli = "gross" }
local renamedFoodSet = scope:ForKeys(foodSet, function(use, scope, food)
    return prefixes[food] .. food
end)

foodSet:set({ pie = true })
print(peek(renamedFoodSet)) --> { tasty_pie = true }

foodSet:set({ broccoli = true, chocolate = true })
print(peek(renamedFoodSet)) --> { gross_broccoli = true, yummy_chocolate = true }

You can also use() state objects in your calculations, just like a computed.

local foodSet = scope:Value({ broccoli = true, chocolate = true })

local prefixes = { chocolate = "yummy", broccoli = scope:Value("gross") }
local renamedFoodSet = scope:ForKeys(foodSet, function(use, scope, food)
    return use(prefixes[food]) .. food
end)

print(peek(renamedFoodSet)) --> { gross_broccoli = true, yummy_chocolate = true }

prefixes.broccoli:set("scrumptious")
print(peek(renamedFoodSet)) --> { scrumptious_broccoli = true, yummy_chocolate = true }

Anything added to the scope is cleaned up for you when the processed key is removed.

local foodSet = scope:Value({ broccoli = true, chocolate = true })

local shoutingFoodSet = scope:ForKeys(names, function(use, scope, food)
    table.insert(scope, function()
        print("I ate the " .. food .. "!")
    end)
    return string.upper(food)
end)

names:set({ chocolate = true }) --> I ate the broccoli!
How ForKeys optimises your code

Rather than creating a new output table from scratch every time the input table is changed, ForKeys will try and reuse as much as possible to improve performance.

Say you're converting an array to a dictionary:

local array = scope:Value({"Fusion", "Knit", "Matter"})
local dict = scope:ForKeys(array, function(use, scope, index)
    return "Value" .. index
end)

print(peek(dict)) --> {Value1 = "Fusion", Value2 = "Knit", Value3 = "Matter"}

Because ForKeys only operates on the keys, changing the values in the array doesn't affect the keys. Keys are only added or removed as needed:

local array = scope:Value({"Fusion", "Knit", "Matter"})
local dict = scope:ForKeys(array, function(use, scope, index)
    return "Value" .. index
end)

print(peek(dict)) --> {Value1 = "Fusion", Value2 = "Knit", Value3 = "Matter"}

array:set({"Roact", "Rodux", "Promise"})
print(peek(dict)) --> {Value1 = "Roact", Value2 = "Rodux", Value3 = "Promise"}

ForKeys takes advantage of this - when a value changes, it's copied into the output table without recalculating the key. Keys are only calculated when a value is assigned to a new key.

Back to top