I feel like my react-lua code is messy and bad, how do I get better at writing it?

So, I’m trying to move to react-lua to make my UI less buggy and janky. Issue is, I feel like this code is super messy and ugly. I’m struggling to read it/wrap my head around it, and it’s my own code. I’m wondering if any of y’all have advice on writing it.

For context, all this code is for 5 elements so far.

local player = game:GetService("Players").LocalPlayer
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Roact = ReplicatedStorage:WaitForChild("Roact")
local React = require(Roact:WaitForChild("React"))
local ReactRoblox = require(Roact:WaitForChild("ReactRoblox"))

local PRIMARY_TEXT_COLOR = Color3.new(0.0117647, 0.670588, 0)
local PRIMARY_FONT = Font.fromName("PressStart2P")

local function TerminalTextButton(props)
	return React.createElement("TextButton", {
		Text = "> "..props.text,
		Size = props.size,
		Position = props.position,
		BorderSizePixel = 0,
		FontFace = PRIMARY_FONT,
		TextColor3 = PRIMARY_TEXT_COLOR,
		TextXAlignment = Enum.TextXAlignment.Left,
		BackgroundTransparency = 1,
		TextScaled = true,
		[React.Event.Activated] = function()

		end
	})
end

local function TitleScreen() 
	return React.createElement("Frame", {
		Size = UDim2.new(1,0,1,0),
		BackgroundColor3 = Color3.new(0, 0, 0),
		BorderSizePixel = 0,
	}, {
		React.createElement("ImageLabel",{
			Size = UDim2.fromScale(0.5,0.5),
			Position = UDim2.fromScale(0.5,0),
			AnchorPoint = Vector2.new(0.5,0),
			BorderSizePixel = 0,
			BackgroundTransparency = 1,
			Image = "rbxassetid://134510408138841",
			ImageColor3 = PRIMARY_TEXT_COLOR,
			ScaleType = Enum.ScaleType.Fit,
			ResampleMode = Enum.ResamplerMode.Pixelated,
		}),
		React.createElement("Frame", {
			BackgroundTransparency = 1,
			Size = UDim2.fromScale(0.25, .5),
			Position = UDim2.fromScale(0,.5)
		}, {React.createElement("UIGridLayout",{
				CellPadding = UDim2.fromOffset(0,5),
				CellSize = UDim2.fromScale(1,0.12),
				FillDirection = Enum.FillDirection.Vertical
		}),
			React.createElement(TerminalTextButton,{
				size = UDim2.fromScale(1,0.07),
				text = "Play",
				position = UDim2.fromScale(0,0)
			}),
		})
	})
end

local handle = Instance.new("ScreenGui", player.PlayerGui)
handle.IgnoreGuiInset = true
local root = ReactRoblox.createRoot(handle)
root:render(React.createElement(TitleScreen, {}, {}))

That can’t be optimal code for something this basic, that doesn’t even have functionality yet. Right?

image

1 Like

that’s kinda how it works ifyou use react-lua to make guis
i dont know about scripting but i think the code will be more optimal if you just make the guis and design it yourself

1 Like

I get where you’re coming from, it feels like a lot of code for minimal outcome. But, at least for me, the main reason for using React-lua is the reusability of the components you make. Which translates into a bit more work in the beginning and a less work later in the process.

In your code example, you’re making every element inside one script, but I would recommend splitting them up into separate scripts so you can reuse the components you make in the future.

For example; in most cases where I want to use an imagelabel, I really only need to specify the ImageURL, so it is annoying to have to set the position and anchor point every time.

So instead, I’ll make a new script SimpleImage.lua:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local React = require(ReplicatedStorage.Packages.React)

local function SimpleImage(props: {})
    return React.createElement("ImageButton", {
        Image = props.image,
        Size = props.size or UDim2.new(1, 0, 1, 0),
        BackgroundTransparency = props.BackgroundTransparency or 1,
        Position = props.position or UDim2.new(0.5, 0, 0.5, 0),
        AnchorPoint = props.anchorPoint or Vector2.new(0.5, 0.5),
        ScaleType = props.scaleType or Enum.ScaleType.Fit,
    }, {})
end

return SimpleImage

Now if I want to add an image anywhere in my code I can just use this component and only alter the props that I want to alter:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local React = require(ReplicatedStorage.Packages.React)

local SimpleImage = require(ReplicatedStorage.UI.SimpleImage)

local function TitleScreen()
	return React.createElement("Frame", {
		Size = UDim2.fromScale(1, 1),
	}, {
	    SomeImage = React.createElement(SimpleImage, {
			image = "rbxassetid://1002184426",
		})
	})
end

return TitleScreen

I hope that helps!

Two small tricks;

  1. To make your code more readable, the Roblox react-lua community often declare createElement as follows: local e = React.createElement. This feels a bit weird using at first but it really helps. For example, the script above:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local React = require(ReplicatedStorage.Packages.React)

local SimpleImage = require(ReplicatedStorage.UI.SimpleImage)

local e = React.createElement

local function Lobby()
	return e("Frame", {
		Size = UDim2.fromScale(1, 1),
	}, {
		Image = e(SimpleImage, {
			image = "rbxassetid://1002184426",
		})
	})
end

return Lobby

Small difference here, but in big scripts it massively increases readability.

  1. In the second dict of React.createElement, if you add a key, it will rename the instance of that element automatically. For example:
e("Frame", {}, { 
    UIGridLayout = e("UIGridLayout", {}, {}),
    SomeButton = e("UIButton", {}, {
        Text = e("TextLabel", {}, {})
    }),
})

Will look like;

image

5 Likes

Thank you so much, this will help a lot! For separating the script into multiples, should I have seperate modules for different kinds of elements? Say for example that I had a bunch of basic elements that get used in other elements, would I separate those into their own module?

Yeah thats the general idea. As @Ninsky_12 said react is a slow start for a big payoff in the future.

Recently i decided that the my ui style really wasnt working for a game im working on, and it took about 10 minutes to change the entire games ui style from a retro-arcade blue to a sleek modern black (with curved corners). It really is great for maintainability.

2 Likes

Please don’t do this. The reason it feels a weird is because it’s degrading the quality of your code through inconsistencies in naming conventions and improper naming of variables. There’s a really good video by CodeAesthetic that dives into naming variables (https://youtu.be/-J3wNP6u5YU?si=zCUp05WcW83vKyLH), but here’s a short list of reasons not just create a single letter abbreviation for functions:

  1. Readability, makes the code harder for any onlookers to read and understand the code without going back up and reading what the functions actually equal.
    (Next thing you know you end up with code like this:)

  2. Not to mention that a single letter abbreviation is already very obscure and can mean various different things. If anything ce for create element would be more appropriate, as e alone doesn’t convey any information.

  3. Local function dependencies, if you’re porting portions of the code between scripts you’ll have to not only include the react dependency, from an organizational standpoint this requires more maintenance and just more lines of code that need to be copied around.

1 Like

I do agree in most other cases. Naming functions as single letters is bad for readability.

However, I did not personally make up this name. It is a bit of a roblox community standard to do it this way. Because it massively improves readability. Other dev’s working in react-lua will probably recognise this standard.

I haven’t programmed in react-lua for very long though, so I’ll refer to this doc of someone with a lot more experience than me! :slight_smile:

(I’ve altered my original comment to make it more clear, because it indeed seems like I just made it up)

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.