Instance Handling
Components are a good fit for Roblox instances. You can assemble complex groups of instances by combining simpler, self-contained parts.
To ensure maximum compatibility, there are a few best practices to consider.
Returns¶
Anything you return from a component should be supported by
[Children]
.
-- returns an instance
return scope:New "Frame" {}
-- returns an array of instances
return {
scope:New "Frame" {},
scope:New "Frame" {},
scope:New "Frame" {}
}
-- returns a state object containing instances
return scope:ForValues({1, 2, 3}, function(use, scope, number)
return scope:New "Frame" {}
end)
-- mix of arrays, instances and state objects
return {
scope:New "Frame" {},
{
scope:New "Frame" {},
scope:ForValues( ... )
}
scope:ForValues( ... )
}
Returning multiple values is fragile
Don't return multiple values directly from your function. When a function returns multiple values directly, the extra returned values can easily get lost.
local function BadThing(scope, props)
-- returns *multiple* instances (not surrounded by curly braces!)
return
scope:New "Frame" {},
scope:New "Frame" {},
scope:New "Frame" {}
end
local things = {
-- Luau doesn't let you add multiple returns to a list like this.
-- Only the first Frame will be added.
scope:BadThing {},
scope:New "TextButton" {}
}
print(things) --> { Frame, TextButton }
Instead, you should return them inside of an array. Because the array is a single return value, it won't get lost.
If your returns are compatible with [Children]
like above, you can insert a
component anywhere you'd normally insert an instance.
You can pass in one component on its own...
local ui = scope:New "ScreenGui" {
[Children] = scope:Button {
Text = "Hello, world!"
}
}
...you can include components as part of an array..
local ui = scope:New "ScreenGui" {
[Children] = {
scope:New "UIListLayout" {},
scope:Button {
Text = "Hello, world!"
},
scope:Button {
Text = "Hello, again!"
}
}
}
...and you can return them from state objects, too.
local stuff = {"Hello", "world", "from", "Fusion"}
local ui = scope:New "ScreenGui" {
[Children] = {
scope:New "UIListLayout" {},
scope:ForValues(stuff, function(use, scope, text)
return scope:Button {
Text = text
}
end)
}
}
Containers¶
Some components, for example pop-ups, might contain lots of different content:
Ideally, you would be able to reuse the pop-up 'container', while placing your own content inside.
The simplest way to do this is to pass instances through to [Children]
. For
example, if you accept a table of props
, you can add a [Children]
key:
local function PopUp(
scope: Fusion.Scope,
props: {
[typeof(Children)]: Fusion.Children
}
)
return scope:New "Frame" {
[Children] = props[Children]
}
end
Accepting multiple instances
If you have multiple 'slots' where you want to pass through instances, you
can make other properties and give them the Fusion.Children
type.
Later on, when a pop-up is created, instances can now be parented into that pop-up:
scope:PopUp {
[Children] = {
scope:Label {
Text = "New item collected"
},
scope:ItemPreview {
Item = Items.BRICK
},
scope:Button {
Text = "Add to inventory"
}
}
}
If you need to add other instances, you can still use arrays and state objects as normal. You can include instances you're given, in exactly the same way you would include any other instances.
scope:New "Frame" {
-- ... some other properties ...
[Children] = {
-- the component provides some children here
scope:New "UICorner" {
CornerRadius = UDim.new(0, 8)
},
-- include children from outside the component here
props[Children]
}
}