[Roact] -- Change Button color on click, go back to its original color when another button is clicked

As I’m developing my game’s interface using Roact, I’m now working on the Pause Menu, which has led up to me being stuck in where I have no clue how to make a button go back to its original state when another button is clicked.

I’ve reached out to multiple friends of mine, with contribution from one of them, I’m now using ‘Signal’ to handle each click event. However, I haven’t reached a complete solution.

For demonstration, I’m only trying to figure this out with the ‘Map’ and ‘Shop’ button.
Here’s a video on how it’s working right now:
https://gyazo.com/026c70a9e69a85391f578f7f603c9402

If you have any experience with Roact and can help me out, it’d be much appreciated!

local Button = Roact.Component:extend("Button")
local ButtonMagic = Signal.new()

function Button:init()
	self:setState({
		visible = false,
		isClicked = false,
		textColor = Color3.new(1, 1, 1),
		backgroundColor = Color3.new(0.113725, 0.113725, 0.113725)
	})
	
	local LastButtonEventName = ""

	ButtonMagic:Connect(function(Name)
		if LastButtonEventName == "" then
			LastButtonEventName = Name
		elseif (LastButtonEventName == Name) then
			print("same button pressed")
			-- same button was pressed so perhaps disable?
		elseif (Name and LastButtonEventName ~= Name ) then
			print("must be new button" .. " new name of button: " .. Name)

			-- code here


			LastButtonEventName = Name

		end

	end)
end

function Button:render()
	return Roact.createElement("TextButton", {
		Text = self.props.name,
		Font = Enum.Font.SourceSansBold,
		TextSize = 17,
		TextScaled = false,
		TextColor3 = self.state.textColor,
		BorderSizePixel = 0,
		BackgroundColor3 = self.state.backgroundColor,
		[Roact.Event.MouseButton1Click] = function()
			function self.props.onClick()
				if self.props.name == "Map" then
					self:setState({
						visible = not self.state.visible,
						isClicked = true,
						textColor = Color3.new(0, 0, 0),
						backgroundColor = Color3.new(1, 1, 1),
					})
					if not self.state.visible then
						self:setState({
							isClicked = false,
							textColor = Color3.new(1, 1, 1),
							backgroundColor = Color3.new(0.113725, 0.113725, 0.113725)
						})
					end	
					ButtonMagic:Fire("Map")
				elseif self.props.name == "Shop" then
					self:setState({
						visible = not self.state.visible,
						isClicked = true,
						textColor = Color3.new(0, 0, 0),
						backgroundColor = Color3.new(1, 1, 1),
					})
					if not self.state.visible then
						self:setState({
							isClicked = false,
							textColor = Color3.new(1, 1, 1),
							backgroundColor = Color3.new(0.113725, 0.113725, 0.113725)
						})
					end	
					ButtonMagic:Fire("Shop")

				end
			end
			if (self.props.onClick ~= nil) then
				self.props.onClick()
			end
		end,
	}, {
		Roact.createElement("Frame", {
			Size = UDim2.new(0, 100, 0, 3),
			Visible = self.state.visible,
			Position = UDim2.new(0.151, 0, 1.1, 0),
			BorderSizePixel = 0,
			BackgroundColor3 = Color3.new(1, 1, 1),
		})
	})
end

Ok, a couple things…
I would recommend using Bindings, not state here. Bindings are a little easier to work with, and it’ll look cleaner.
What I would do is use the Component that is actually creating the button handle the clicks, and send a prop that is an OnClicked function to change the state on the main one. It’ll be something like this"

-- main.lua
function main:render()
    return createElement(btn, {
        name = "SomeNameHere",
        OnClicked = function(name)
            self:setState({
                activeButton = name,
            })
        end,
        active = self.state.activeButton == "SomeNameHere"
    })
end

-- button.lua
function button:init()
    function self.onBtnClick()
        self.props.OnActivated(self.props.name)
    end
end

function button:render()
    -- props.active will tell whether or not it is the active one
    return createElement("...", {
        [Roact.Event.MouseClick] = self.onBtnClick,
    })
end
1 Like

State is always easier to work with. Bindings don’t exist in upstream and only exist as a roblox deviation to optimize rapidly changing updates.

1 Like