API Reference
Methods¶
Roact.createElement¶
Roact.createElement(component, [props, [children]]) -> RoactElement
Creates a new Roact element representing the given component
. Elements are lightweight descriptions about what a Roblox Instance should look like, like a blueprint!
The children
argument is shorthand for adding a Roact.Children
key to props
. It should be specified as a dictionary of names to elements.
component
can be a string, a function, or a table created by Component:extend
.
Caution
Make sure not to modify props
or children
after they're passed into createElement
!
Roact.createFragment¶
Added in Roact 1.0.0
Roact.createFragment(elements) -> RoactFragment
Creates a new Roact fragment with the provided table of elements. Fragments allow grouping of elements without the need for intermediate containing objects like Frame
s.
Caution
Make sure not to modify elements
after they're passed into createFragment
!
Roact.mount¶
Roact.mount(element, [parent, [key]]) -> RoactTree
Info
Roact.mount
is also available via the deprecated alias Roact.reify
. It will be removed in a future release.
Creates a Roblox Instance given a Roact element, and optionally a parent
to put it in, and a key
to use as the instance's Name
.
The result is a RoactTree
, which is an opaque handle that represents a tree of components owned by Roact. You can pass this to APIs like Roact.unmount
. It'll also be used for future debugging APIs.
Roact.update¶
Roact.update(tree, element) -> RoactTree
Info
Roact.update
is also available via the deprecated alias Roact.reconcile
. It will be removed in a future release.
Updates an existing instance handle with a new element, returning a new handle. This can be used to update a UI created with Roact.mount
by passing in a new element with new props.
update
can be used to change the props of a component instance created with mount
and is useful for putting Roact content into non-Roact applications.
As of Roact 1.0, the returned RoactTree
object will always be the same value as the one passed in.
Roact.unmount¶
Roact.unmount(tree) -> void
Info
Roact.unmount
is also available via the deprecated alias Roact.teardown
. It will be removed in a future release.
Destroys the given RoactTree
and all of its descendants. Does not operate on a Roblox Instance -- this must be given a handle that was returned by Roact.mount
.
Roact.oneChild¶
Roact.oneChild(children) -> RoactElement | nil
Given a dictionary of children, returns a single child element.
If children
contains more than one child, oneChild
function will throw an error. This is intended to denote an error when using the component using oneChild
.
If children
is nil
or contains no children, oneChild
will return nil
.
Roact.createBinding¶
Added in Roact 1.0.0
Roact.createBinding(initialValue) -> Binding, updateFunction
where
updateFunction: (newValue) -> ()
The first value returned is a Binding
object, which will typically be passed as a prop to a Roact host component. The second is a function that can be called with a new value to update the binding.
A Binding
has the following API:
getValue¶
Binding:getValue() -> value
Returns the internal value of the binding. This is helpful when updating a binding relative to its current value.
Warning
Using getValue
inside a component's render
method is dangerous! Using the unwrapped value directly won't allow Roact to subscribe to a binding's updates. To guarantee that a bound value will update, use the binding itself for your prop value.
map¶
Binding:map(mappingFunction) -> Binding
where
mappingFunction: (value) -> mappedValue
Returns a new binding that maps the existing binding's value to something else. For example, map
can be used to transform an animation progress value like 0.4
into a property that can be consumed by a Roblox Instance like UDim2.new(0.4, 0, 1, 0)
.
Roact.joinBindings¶
Added in Roact 1.1.0
Roact.joinBindings(bindings) -> Binding
where
bindings: { [any]: Binding }
Combines multiple bindings into a single binding. The new binding's value will have the same keys as the input table of bindings.
joinBindings
is usually used alongside Binding:map
:
local function Flex()
local aSize, setASize = Roact.createBinding(Vector2.new())
local bSize, setBSize = Roact.createBinding(Vector2.new())
return Roact.createElement("Frame", {
Size = Roact.joinBindings({aSize, bSize}):map(function(sizes)
local sum = Vector2.new()
for _, size in ipairs(sizes) do
sum = sum + size
end
return UDim2.new(0, sum.X, 0, sum.Y)
end),
}, {
A = Roact.createElement("Frame", {
Size = UDim2.new(1, 0, 0, 30),
[Roact.Change.AbsoluteSize] = function(instance)
setASize(instance.Size)
end,
}),
B = Roact.createElement("Frame", {
Size = UDim2.new(1, 0, 0, 30),
Position = aSize:map(function(size)
return UDim2.new(0, 0, 0, size.Y)
end),
[Roact.Change.AbsoluteSize] = function(instance)
setBSize(instance.Size)
end,
}),
})
end
Roact.createRef¶
Roact.createRef() -> Ref
Creates a new reference object that can be used with Roact.Ref.
Roact.forwardRef¶
Added in Roact 1.4.0
Roact.forwardRef(render: (props: table, ref: Ref) -> RoactElement) -> RoactComponent
Creates a new component given a render function that accepts both props and a ref, allowing a ref to be forwarded to an underlying host component via Roact.Ref.
Roact.createContext¶
Added in Roact 1.3.0
Roact.createContext(defaultValue: any) -> RoactContext
type RoactContext = {
Provider: Component,
Consumer: Component,
[private fields]
}
Creates a new context provider and consumer. For a usage guide, see Advanced Concepts: Context.
defaultValue
is given to consumers if they have no Provider
ancestors. It is up to users of Roact's context API to turn this case into an error if it is an invalid state.
Provider
and Consumer
are both Roact components.
Provider
¶
Provider
accepts the following props:
value
: The value to put into the tree for this context value.- If the
Provider
is updated with a newvalue
, any matchingConsumer
components will be re-rendered with the new value.
- If the
[Children]
: Any number of children to render underneath this provider.- Descendants of this component can receive the provided context value by using
Consumer
.
- Descendants of this component can receive the provided context value by using
Consumer
¶
Consumer
accepts just one prop:
render(value) -> RoactElement | nil
: A function that will be invoked to render any children.render
will be called every timeConsumer
is rendered.
Roact.setGlobalConfig¶
Roact.setGlobalConfig(configValues: Dictionary<string, bool>) -> void
The entry point for configuring Roact. Roact currently applies this to everything using this instance of Roact, so be careful using this with a project that has multiple consumers of Roact.
Once config values are set, they will apply from then on. This is primarily useful when developing as it can enable features that validate your code more strictly. Most of the settings here incur a performance cost and should typically be disabled in production environments.
Call this method once at the root of your project (before mounting any Roact elements):
Roact.setGlobalConfig({
typeChecks = true,
propValidation = true,
})
The following are the valid config keys that can be used, and what they do.
typeChecks¶
Enables type checks for Roact's public interface. This includes some of the following:
- Check that the
props
andchildren
arguments toRoact.createElement
are both tables or nil - Check that
setState
is passingself
as the first argument (it should be called likeself:setState(...)
) - Confirm the
Roact.mount
's first argument is a Roact element - And much more!
internalTypeChecks¶
Enables type checks for internal functionality of Roact. This is typically only useful when debugging Roact itself. It will run similar type checks to those mentioned above, but only the private portion of the API.
elementTracing¶
When enabled, Roact will capture a stack trace at the site of each element creation and hold onto it, using it to provide additional details on certain kinds of errors. If you get an error that says "
Enabling elementTracing
also allows the use of the getElementTraceback method on Component, which can also be helpful for debugging.
propValidation¶
Enables validation of props via the validateProps method on components. With this flag enabled, any validation written by component authors in a component's validateProps
method will be run on every prop change. This is helpful during development for making sure components are being used correctly.
Constants¶
Roact.Children¶
This is the key that Roact uses internally to store the children that are attached to a Roact element.
If you're writing a new function component or stateful component that renders children like a host component, you can access Roact.Children
in your props table.
Roact.Ref¶
Use Roact.Ref
as a key into the props of a host element to receive a handle to the underlying Roblox Instance.
Assign this key to a ref created with createRef:
local ExampleComponent = Roact.Component:extend("ExampleComponent")
function ExampleComponent:init()
-- Create a ref.
self.ref = Roact.createRef()
end
function ExampleComponent:render()
return Roact.createElement("Frame", {
-- Use the ref to point to this rendered instance.
[Roact.Ref] = self.ref,
})
end
function ExampleComponent:didMount()
-- Refs are a kind of binding, so we can access the Roblox Instance using getValue.
print("Roblox Instance", self.ref:getValue())
end
Info
Ref objects have a deprecated field called current
that is always equal to the result of getValue
. Assigning to the current
field is not allowed. The field will be removed in a future release.
Alternatively, you can assign it to a function instead:
Roact.createElement("Frame", {
-- The provided function will be called whenever the rendered instance changes.
[Roact.Ref] = function(rbx)
print("Roblox Instance", rbx)
end,
})
Warning
When Roact.Ref
is given a function, Roact does not guarantee when this function will be run relative to the reconciliation of other props. If you try to read a Roblox property that's being set via a Roact prop, you won't know if you're reading it before or after Roact updates that prop!
Warning
When Roact.Ref
is given a function, it will be called with nil
when the component instance is destroyed!
See the refs guide for more details.
Roact.Event¶
Index into Roact.Event
to receive a key that can be used to connect to events when creating host elements:
Roact.createElement("ImageButton", {
[Roact.Event.MouseButton1Click] = function(rbx, x, y)
print(rbx, "clicked at position", x, y)
end,
})
Info
Event callbacks receive the Roblox Instance as the first parameter, followed by any parameters yielded by the event.
Warning
When connecting to the Changed
event, be careful not to call setState
or other functions that will trigger renders. This will cause Roact to re-render during a render, and errors will be thrown!
See the events guide for more details.
Roact.Change¶
Index into Roact.Change
to receive a key that can be used to connect to GetPropertyChangedSignal
events.
It's similar to Roact.Event
:
Roact.createElement("ScrollingFrame", {
[Roact.Change.CanvasPosition] = function(rbx)
print("ScrollingFrame scrolled to", rbx.CanvasPosition)
end,
})
Warning
Property changed events are fired by Roact during the reconciliation phase. Be careful not to accidentally trigger a re-render in the middle of a re-render, or an error will be thrown!
Roact.None¶
Roact.None
is a special value that can be used to clear elements from your component state when calling setState
or returning from getDerivedStateFromProps
.
In Lua tables, removing a field from state is not possible by setting its value to nil
because nil
values mean the same thing as no value at all. If a field needs to be removed from state, it can be set to Roact.None
when calling setState
, which will ensure that the resulting state no longer contains it:
function MyComponent:didMount()
self:setState({
fieldToRemove = Roact.None
})
end
Component Types¶
Roact.Component¶
The base component instance that can be extended to make stateful components.
Call Roact.Component:extend("ComponentName")
to make a new stateful component with a given name.
Roact.PureComponent¶
An extension of Roact.Component
that only re-renders if its props or state change.
PureComponent
implements the shouldUpdate
lifecycle event with a shallow equality comparison. It's optimized for use with immutable data structures, which makes it a perfect fit for use with frameworks like Rodux.
PureComponent
is not always faster, but can often result in significant performance improvements when used correctly.
Roact.Portal¶
A component that represents a portal to a Roblox Instance. Portals are created using Roact.createElement
.
Any children of a portal are put inside the Roblox Instance specified by the required target
prop. That Roblox Instance should not be one created by Roact.
Portals are useful for creating dialogs managed by deeply-nested UI components, and enable Roact to represent and manage multiple disjoint trees at once.
See the Portals guide for a small tutorial and more details about portals.
Component API¶
defaultProps¶
static defaultProps: Dictionary<any, any>
If defaultProps
is defined on a stateful component, any props that aren't specified when a component is created will be taken from there.
init¶
init(initialProps) -> void
init
is called exactly once when a new instance of a component is created. It can be used to set up the initial state
, as well as any non-render
related values directly on the component.
Use setState
inside of init
to set up your initial component state:
function MyComponent:init()
self:setState({
position = 0,
velocity = 10
})
end
In older versions of Roact, setState
was disallowed in init
, and you would instead assign to state
directly. It's simpler to use setState
, but assigning directly to state
is still acceptable inside init
:
function MyComponent:init()
self.state = {
position = 0,
velocity = 10
}
end
render¶
render() -> Element | nil
render
describes what a component should display at the current instant in time.
Info
Roact assumes that render
act likes a pure function: the result of render
must depend only on props
and state
, and it must not have side-effects.
function MyComponent:render()
-- This is okay:
return Roact.createElement("TextLabel", {
Text = self.props.text,
Position = self.state.position
})
-- Ack! Depending on values outside props/state is not allowed!
return Roact.createElement("TextLabel", {
Text = self.someText,
Position = getMousePosition(),
})
end
render
must be defined for all components. The default implementation of render
throws an error; if your component does not render anything, define a render function that returns nil
explicitly. This helps make sure that you don't forget to define render
!
function MyComponent:render()
return nil
end
setState¶
setState(stateUpdater | stateChange) -> void
setState
requests an update to the component's state. Roact may schedule this update for a later time or resolve it immediately.
If a function is passed to setState
, that function will be called with the current state and props as arguments:
function MyComponent:didMount()
self:setState(function(prevState, props)
return {
counter = prevState.counter + 1
}
end)
end
If this function returns nil
, Roact will not schedule a re-render and no state will be updated.
If a table is passed to setState
, the values in that table will be merged onto the existing state:
function MyComponent:didMount()
self:setState({
foo = "bar"
})
end
Setting a field in the state to Roact.None
will clear it from the state. This is the only way to remove a field from a component's state!
Warning
setState
can be called from anywhere except:
- Lifecycle hooks:
willUnmount
,willUpdate
- Pure functions:
render
,shouldUpdate
Calling setState
inside of init
has special behavior. The result of setState will be used to determine initial state, and no additional updates will be scheduled.
Roact may support calling setState
in currently-disallowed places in the future.
Warning
setState
does not always resolve synchronously! Roact may batch and reschedule state updates in order to reduce the number of total renders.
When depending on the previous value of state, like when incrementing a counter, use the functional form to guarantee that all state updates occur!
This behavior will be similar to the future behavior of React 17. See:
shouldUpdate¶
shouldUpdate(nextProps, nextState) -> bool
shouldUpdate
provides a way to override Roact's rerendering heuristics.
By default, components are re-rendered any time a parent component updates, or when state is updated via setState
.
PureComponent
implements shouldUpdate
to only trigger a re-render any time the props are different based on shallow equality. In a future Roact update, all components may implement this check by default.
validateProps¶
Added in Roact 1.0.0
static validateProps(props) -> (false, message: string) | true
validateProps
is an optional method that can be implemented for a component. It provides a mechanism for verifying inputs passed into the component.
Every time props are updated, validateProps
will be called with the new props before proceeding to shouldUpdate
or init
. It should return the same parameters that assert expects: a boolean, true if the props passed validation, false if they did not, plus a message explaining why they failed. If the first return value is true, the second value is ignored.
For performance reasons, property validation is disabled by default. To use this feature, enable propValidation
via setGlobalConfig
:
Roact.setGlobalConfig({
propValidation = true
})
See setGlobalConfig for more details.
Note
validateProps
is a static lifecycle method. It does not have access to self
, and must be a pure function.
Warning
Depending on the implementation, validateProps
can impact performance. Recommended practice is to enable prop validation during development and leave it off in production environments.
getElementTraceback¶
getElementTraceback() -> string | nil
getElementTraceback
gets the stack trace that the component was created in. This allows you to report error messages accurately.
Lifecycle Methods¶
In addition to the base Component API, Roact exposes additional lifecycle methods that stateful components can hook into to be notified of various steps in the rendering process.
didMount¶
didMount() -> void
didMount
is fired after the component finishes its initial render. At this point, all associated Roblox Instances have been created, and all components have finished mounting.
didMount
is a good place to start initial network communications, attach events to services, or modify the Roblox Instance hierarchy.
willUnmount¶
willUnmount() -> void
willUnmount
is fired right before Roact begins unmounting a component instance's children.
willUnmount
acts like a component's destructor, and is a good place to disconnect any manually-connected events.
willUpdate¶
willUpdate(nextProps, nextState) -> void
willUpdate
is fired after an update is started but before a component's state and props are updated.
didUpdate¶
didUpdate(previousProps, previousState) -> void
didUpdate
is fired after at the end of an update. At this point, Roact has updated the properties of any Roblox Instances and the component instance's props and state are up to date.
didUpdate
is a good place to send network requests or dispatch Rodux actions, but make sure to compare self.props
and self.state
with previousProps
and previousState
to avoid triggering too many updates.
getDerivedStateFromProps¶
static getDerivedStateFromProps(nextProps, lastState) -> nextStateSlice
Used to recalculate any state that depends on being synchronized with props
.
Generally, you should use didUpdate
to respond to props changing. If you find yourself copying props values to state as-is, consider using props or memoization instead.
getDerivedStateFromProps
should return a table that contains the part of the state that should be updated.
function MyComponent.getDerivedStateFromProps(nextProps, lastState)
return {
someValue = nextProps.someValue
}
end
As with setState
, you can set use the constant Roact.None
to remove a field from the state.
Note
getDerivedStateFromProps
is a static lifecycle method. It does not have access to self
, and must be a pure function.
Caution
getDerivedStateFromProps
runs before shouldUpdate
and any non-nil return will cause the state table to no longer be shallow-equal. This means that a PureComponent
will rerender even if nothing actually changed. Similarly, any component implementing both getDerivedStateFromProps
and shouldUpdate
needs to do so in a way that takes this in to account.