Invalid Prop Discarding
All of the following behaviour can be disabled entirely by setting invalidPropDiscarding
to false
in Roact:setGlobalConfig()
. Functionality will return to being the same as Roblox's version, including any warnings or errors.
As mentioned in the last section, passing in an invalid prop into a host component does not error like in regular Roact. While this has its drawbacks — notably making it harder to spot invalid props intended to actually be properties and the inability to use typeChecks
— this helps massively with overriding a component's default props without having to use sanitiser functions.
Why?¶
Normally, to override default component props, you might do the following:
-- component code
function Button(props)
local fullProps = {
BackgroundColor3 = Color3.new(1, 0, 1),
Size = UDim2.new(0, 100, 0, 50),
Text = "Placeholder text",
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
}
for k, v in props do
fullProps[k] = v
end
return Roact.createElement("TextButton", fullProps)
end
-- adding to/overriding default props
local buttonElement = Roact.createElement(Button, {
AnchorPoint = Vector2.new(0.5, 0.5),
Size = UDim2.new(0, 600, 0, 400),
Text = "Overriden text",
})
This can work at first, but issues arise when you want to use props other than the host components available properties:
function Button(props)
local fullProps = {
BackgroundColor3 = Color3.new(1, 0, 1),
FontFace = Font.fromName("FredokaOne", props.FontStyle)
Size = UDim2.new(0, 100, 0, 50),
Text = "Placeholder text",
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
}
for k, v in props do
fullProps[k] = v
end
return Roact.createElement("TextButton", fullProps)
end
This code looks fine at first, but during the for
loop, it gets added to fullProps
, thereby passing it as a prop into TextButton
, which will error. You could override the FontFace
prop itself, but if you ever want to change the font across the whole game (or at least every Button
), then you have to go change every override of it instead of just in the component itself. The hassle of this stacks up the more complex your components are. The same applies to adding an exception for FontStyle
in the for
loop, but again the more invalid props there are, the larger the hassle of this is.
Another point at which this becomes a drag is when there are multiple versions of the same component, e.g. a secondary button. You could make a BaseButton
component and extend your primary and secondary buttons from that, but should you also introduce active and inactive buttons, you'll have to make 4 separate components, which all have to incorporate the same merger for
loop or any other shared logic across them, which isn't very D.R.Y.
Sometimes, invalid props may even have nothing to do with the actual style of the component itself, instead incorporating some other logic in them. In this example, it fires a RemoteEvent
:
function Button(props)
local fullProps = {
BackgroundColor3 = Color3.new(1, 0, 1),
Size = UDim2.new(0, 100, 0, 50),
Text = "Placeholder text",
TextColor3 = Color3.new(1, 1, 1),
TextStrokeColor3 = Color3.new(0, 0, 0),
}
if props.IsASpecialButton then
ReplicatedStorage.RemoteEvent:FireServer("Special button rendered!")
end
for k, v in props do
fullProps[k] = v
end
return Roact.createElement("TextButton", fullProps)
end
In cases such as these, it's mostly a convenience for Roact to simply skip over invalid props when applying them to actual Roblox instances, rather than create impractical workarounds to both be able to add to and override default component props and incorporate extra logic based on props.