Roact Exploding (Infinite Recursion error) (?)

Just before I start, I’m really new to Roact but I value the features that it supports so I’m trying to implement it.

I wanted to use a component within a component (as a function) so I can automatically add a shadow effect behind my TextLabels. Here is my code for that (it’s autocompiled from roblox-ts so excuse the weird indenting and semicolons)


local function TextLabelWithBacking(Props)
	local subProps = Props;
	subProps.Position = UDim2.new(0, 0, 0, 2);
	subProps.Size = UDim2.new(1, 0, 1, 0);
	subProps.TextColor3 = Props.TextColor3:Lerp(Color3.new(0, 0, 0), .75);
	return Roact.createElement("TextLabel", Props, {
		Back = Roact.createElement("TextLabel", subProps);
	});
end;
local function Detain(props)
	local username = props.username;
	return Roact.createElement("ScreenGui", {
		ZIndexBehavior = Enum.ZIndexBehavior.Global,
		ResetOnSpawn = false 
	}	, {
		["Detain"] = Roact.createElement(TextLabelWithBacking, {
			Size = UDim2.new(1, 0, 0, 50),
			BackgroundTransparency = 1,
			Font = Enum.Font.GothamBold,
			TextScaled = true,
			Position = UDim2.new(0, 0, .5, 0),
			AnchorPoint = Vector2.new(0, 0.5),
			TextColor3 = Color3.new(1, 1, 1),
			ZIndex = 2,
			Text = "You are being detained by " .. username .. "." 
		}		, {
			["SubHeader"] = Roact.createElement(TextLabelWithBacking, {
				Size = UDim2.new(.5, 0, 0, 30),
				Position = UDim2.new(0.5, 0, 1, 0),
				TextScaled = true,
				ZIndex = 2,
				AnchorPoint = Vector2.new(.5, 0),
				BackgroundTransparency = 1,
				Font = Enum.Font.GothamBold,
				TextColor3 = Color3.new(1, 1, 1),
				Text = "Your weapons are now useless." 
			}			, {

			})
		})
	});
end;

For some reason that I’m unable to traceback since this crashes my studio in test mode and produces this unhelpful stack trace:

Can anyone with experience with Roact let me know where I’m going wrong? I’m unable to find anything different in the docs to what I’m doing.

1 Like

I believe the issue is because the children table is actually part of props. I.e., in this:

Roact.createElement(TextLabelWithBacking, {
    Text = "Hello, World!",
}, {
    SubHeader = Roact.createElement(TextLabelWithBacking, {
        Text = "test",
    }),
})

The props passed to the first TextLabelWithBacking, look like:

{
    Text = "Hello, World",
    [Roact.Children] = {
        SubHeader = ...,
    }
}

So then in TextLabelWithBacking, where you pass both props with a children table, and a new children table to your outer TextLabel, Roact throws an error.

Here’s a possible solution (not tested, on phone):

-- Join multiple dictionaries without mutating any
local function dictJoin(...)
    local result = {}
    for _, tbl in ipairs({...}) do
        for k, v in pairs(tbl) do
            result[k] = v
        end
    end
    return result
end

local function TextLabelWithBacking(props)
    -- Join with nothing to copy
    local topProps = dictJoin(props)
    topProps[Roact.Children] = nil

    local subProps = dictJoin(props, {
        Position = UDim2.new(0, 0, 0, 2),
        Size = UDim2.new(1, 0, 1, 0),
        TextColor3 = props.TextColor3:Lerp(Color3.fromRGB(0, 0, 0), 0.75),
    })

    local children = props[Roact.Children]

    return Roact.createElement("TextLabel", topProps, {
        Back = Roact.createElement("TextLabel", subProps, children),
    })
end
2 Likes

This works! Now to work out how to make it work in TypeScript :thinking:

3 Likes