Context
Added in Roact 1.3.0
Roact supports a feature called context which enables passing values down the tree without having to pass them through props. Roact's Context API is based on React's Context API.
Context is commonly used to implement features like dependency injection, dynamic theming, and scoped state storage.
Basic Usage¶
local ThemeContext = Roact.createContext(defaultValue)
Context objects contain two components, Consumer
and Provider
.
The Consumer
component accepts a render
function as its only prop, which is used to render its children. It's passed one argument, which is the context value from the nearest matching Provider
ancestor.
If there is no Provider
ancestor, then defaultValue
will be passed instead.
local function ThemedButton(props)
return Roact.createElement(ThemeContext.Consumer, {
render = function(theme)
return Roact.createElement("TextButton", {
Size = UDim2.new(0, 100, 0, 100),
Text = "Click Me!",
TextColor3 = theme.foreground,
BackgroundColor3 = theme.background,
})
end
})
end
The Provider
component accepts a value
prop as well as children. Any of its descendants will have access to the value provided to it by using the Consumer
component like above.
Whenever the Provider
receives a new value
prop in an update, any attached Consumer
components will re-render with the new value. This value could be externally controlled, or could be controlled by state in a component wrapping Provider
:
local ThemeController = Roact.Component:extend("ThemeController")
function ThemeController:init()
self:setState({
theme = {
foreground = Color3.new(1, 1, 1),
background = Color3.new(0, 0, 0),
}
})
end
function ThemeController:render()
return Roact.createElement(ThemeContext.Provider, {
value = self.state.theme,
}, self.props[Roact.Children])
end
Danger
Legacy Context is a deprecated feature that will be removed in a future release of Roact.
Roact also has a deprecated version of context that pre-dates the stable context API.
Legacy context values do not update dynamically on their own. It is up to the context user to create their own mechanism for updates, probably using a wrapper component and setState
.
To use it, add new entries to self._context
in Component:init()
to create a provider:
local Provider = Roact.Component:extend("FooProvider")
-- Using a unique non-string key is recommended to avoid collisions.
local FooKey = {}
function Provider:init()
self._context[FooKey] = {
value = 5,
}
end
...and read from that same value in Component:init()
in your consumer component:
local Consumer = Roact.Component:extend("FooConsumer")
function Consumer:init()
self.foo = self._context[FooKey]
end
function Consumer:render()
return Roact.createElement("TextLabel", {
Text = "Foo: " .. self.foo.value,
})
end