Hello Creators!
I am currently coding my User Interface in Roact/React-Lua. I’ve been testing it out and I’m planning on using it my in experiences.
But, when I tried to use Roact in my Module Script, I got the error ReplicatedStorage.ReactLua.node_modules.@jsdotlua.react.ReactHooks:113: attempt to index nil with 'useState'
which sucks because this issue comes from the Roact ModuleScript.
I know that my version of Roact works because I’ve used it in my LocalScript and it worked.
Code
(Note: Not every useState
is shown in the UI Elements)
So the error is on the “first” line of the function “function Profile:CreateUI(createUIProps)
”. Basically, it’s where I defined local isProfileEnabled, setProfileEnabled = React.useState(true)
. But this error happens on any useState
call.
Module Script:
--!strict
-- Variables: Services --
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Variables: Local Player --
local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer.PlayerGui
-- Variables: React --
local React = require(ReplicatedStorage:WaitForChild("ReactLua"):WaitForChild("React"))
local RobloxReact = require(ReplicatedStorage:WaitForChild("ReactLua"):WaitForChild("ReactRoblox"))
-- Variables: Misc --
export type createUIProps = {
DisplayName: string,
Bio: string,
Pronoun1: string,
Pronoun2: string,
IsPlayerVerified: boolean,
IsPlayerDeveloper: boolean,
IsPlayerViewingSelf: boolean,
ProfilePicture: string,
}
local Profile = {}
-- [ Local Functions ] --
-- Create UIPadding --
local function createUIPadding(Properties: any)
return React.createElement("UIPadding", {
PaddingTop = Properties.PaddingTop or UDim.new(0, 0),
PaddingLeft = Properties.PaddingLeft or UDim.new(0, 0),
PaddingRight = Properties.PaddingRight or UDim.new(0, 0),
PaddingBottom = Properties.PaddingBottom or UDim.new(0, 0),
})
end
-- Create UIPadding --
local function createUICorner(Properties: any)
return React.createElement("UIPadding", {
CornerRadius = Properties.CornerRadius or UDim.new(0, 0),
})
end
-- Create UIPadding --
local function createUIListLayout(Properties: any)
return React.createElement("UIListLayout", {
Padding = Properties.Padding or UDim.new(0, 10),
FillDirection = Properties.FillDirection or Enum.FillDirection.Vertical,
SortOrder = Properties.SortOrder or Enum.SortOrder.LayoutOrder,
HorizontalAlignment = Properties.HorizontalAlignment or Enum.HorizontalAlignment.Left,
VerticalAlignment = Properties.VerticalAlignment or Enum.VerticalAlignment.Top
})
end
-- [ Functions ] --
-- createUI --
function Profile:CreateUI(createUIProps)
-- Variables: useState --
local isProfileEnabled, setProfileEnabled = React.useState(true)
local isPronounsEditorEnabled, setPronounsEditorEnabled = React.useState(false)
local pronounsEditorZIndex, setPronounsEditorZIndex = React.useState(1)
local profileZIndex, setProfileZIndex = React.useState(2)
local isEditMode, setEditMode = React.useState(false)
local isPlayerVerified, setPlayerVerified = React.useState(false)
local isPlayerDeveloper, setPlayerDeveloper = React.useState(false)
local isPlayerViewingSelf, setPlayerViewingSelf = React.useState(false)
local pronouns, setPronouns = React.useState({["Pronoun1"] = "", ["Pronoun2"] = "",})
local bio, setBio = React.useState("")
local pronounsEnabled, setPronounsEnabled = React.useState(false)
local playerProfilePicture, setPlayerProfilePicture = React.useState("")
local playerDisplayName, setPlayerDisplayName = React.useState("OnlyTwentyCharacters")
-- Variables: Misc --
local displayName = tostring(createUIProps.DisplayName)
local isPronounsVisible = true
local charCounterColor = #bio > 155 and Color3.new(0.74902, 0.172549, 0.172549) or Color3.new(0, 0, 0)
-- Set Pronouns --
if pronouns.Pronoun1 == "None" and pronouns.Pronoun2 == "None" then
setPronounsEnabled(false)
else
setPronounsEnabled(true)
end
-- Create Elements --
local profileFrame = isProfileEnabled and React.createElement("CanvasGroup", {
Size = UDim2.new(0, 216, 0, 236),
Position = UDim2.new(0.5, 0, 0.5, 0),
BackgroundColor3 = Color3.new(0.988235, 0.937255, 0.937255),
BorderSizePixel = 1,
AnchorPoint = Vector2.new(0.5, 0.5),
AutomaticSize = Enum.AutomaticSize.Y,
ZIndex = profileZIndex,
Name = "frmProfile",
[React.Event.InputBegan] = function(object: Instance, inputObject: InputObject)
setPronounsEditorZIndex(1)
setProfileZIndex(2)
end,
},
{
-- User Inputs --
dragDectector = React.createElement("UIDragDetector", {
BoundingBehavior = Enum.UIDragDetectorBoundingBehavior.Automatic,
DragRelativity = Enum.UIDragDetectorDragRelativity.Absolute,
DragSpace = Enum.UIDragDetectorDragSpace.Parent,
Enabled = true,
}),
-- Styling --
uiStroke = React.createElement("UIStroke", {
ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
Color = Color3.new(0, 0, 0),
LineJoinMode = Enum.LineJoinMode.Round,
Thickness = 2,
Transparency = 0.9
}),
uiPadding1 = React.createElement(createUIPadding, {PaddingBottom = UDim.new(0, 15)}),
uiCorner1 = React.createElement(createUICorner, {CornerRadius = UDim.new(0, 15)}),
-- Layout --
uiListLayout1 = React.createElement(createUIListLayout, {
Padding = UDim.new(0, 10),
FillDirection = Enum.FillDirection.Vertical,
SortOrder = Enum.SortOrder.LayoutOrder,
HorizontalAlignment = Enum.HorizontalAlignment.Center,
VerticalAlignment = Enum.VerticalAlignment.Top
}),
-- Header --
topHeader = React.createElement("Frame", {
Size = UDim2.new(1, 0, 0, 60),
Position = UDim2.new(0, 0, 0, 0),
BorderSizePixel = 0,
BackgroundColor3 = Color3.new(0.321569, 0.611765, 0.929412),
LayoutOrder = 1,
BackgroundTransparency = 0,
},
{...}),
-- Name And Pronouns --
frmNamePronouns = React.createElement("Frame", {
Size = UDim2.new(1, 0, 0, 0),
BorderSizePixel = 0,
BackgroundTransparency = 1,
LayoutOrder = 2,
AutomaticSize = Enum.AutomaticSize.Y
}, {...}),
-- Bio --
defaultBio = not isEditMode and React.createElement("TextLabel", {
Size = UDim2.new(1, 0, 0, 63),
AutomaticSize = Enum.AutomaticSize.Y,
FontFace = Font.new("rbxassetid://12187373327", Enum.FontWeight.Regular, Enum.FontStyle.Normal),
TextSize = 12,
LayoutOrder = 3,
TextColor3 = Color3.new(0, 0, 0),
BackgroundTransparency = 1,
BorderSizePixel = 0,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
Text = tostring(bio),
TextWrapped = true,
}, {...}),
editorBio = isEditMode and React.createElement("TextBox", {
Size = UDim2.new(1, 0, 0, 63),
AutomaticSize = Enum.AutomaticSize.Y,
FontFace = Font.new("rbxassetid://12187373327", Enum.FontWeight.Regular, Enum.FontStyle.Normal),
TextSize = 12,
LayoutOrder = 3,
TextColor3 = Color3.new(0, 0, 0),
BackgroundTransparency = 1,
BorderSizePixel = 0,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
Text = tostring(bio),
TextWrapped = true,
ClearTextOnFocus = false,
[React.Event.Changed] = function(object: TextBox, property: string)
if property == "Text" then
setBio(tostring(object.Text))
end
end,
}, {...}),
bioCharCounter = isEditMode and React.createElement("TextLabel", {
Size = UDim2.new(1, 0, 0, 10),
FontFace = Font.new("rbxassetid://12187373327", Enum.FontWeight.Regular, Enum.FontStyle.Normal),
TextSize = 10,
LayoutOrder = 4,
TextColor3 = charCounterColor,
BackgroundTransparency = 1,
BorderSizePixel = 0,
TextXAlignment = Enum.TextXAlignment.Right,
TextYAlignment = Enum.TextYAlignment.Center,
Text = tostring(#bio).."/155",
TextWrapped = false,
}, {...}),
})
return {profileFrame}
end
return Profile
In this LocalScript, I’m defining and Rooting my User Interface. Previously when I used only a LocalScript to create my UI, it all worked. But it doesn’t seem to work when I use a ModuleScript.
LocalScript
-- Variables: Services --
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Variables: React Lua --
local React = require(ReplicatedStorage:WaitForChild("ReactLua"):WaitForChild("React"))
local RobloxReact = require(ReplicatedStorage:WaitForChild("ReactLua"):WaitForChild("ReactRoblox"))
-- Variables: Modules --
local module = require(ReplicatedStorage:WaitForChild("Modules"):WaitForChild("ReactUI"):WaitForChild("Profile"))
local ui = module:CreateUI()
local props = {
DisplayName = "OnlyTwentyCharacters"
}
local handle = Instance.new("ScreenGui")
handle.Name = "React_ProfileGui"
handle.Parent = Players.LocalPlayer.PlayerGui
handle.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
local root = RobloxReact.createRoot(handle)
root:render(React.createElement(ui, props))
What I’ve Tried
I’m honestly stuck. At most, I’ve moved my lines of code around, but alas, nothing worked. I’m thinking this error might come from how I made my UI render??? But I have no idea.
I’m happy to answer any questions! Thanks in advance!