Skip to content
This repository has been archived by the owner on Dec 13, 2023. It is now read-only.

v1.0.0

Compare
Choose a tag to compare
@LPGhatguy LPGhatguy released this 04 May 00:04
· 89 commits to master since this release

This release is the culmination of almost one year of work improving Roact's internals to pave the way for new features, optimizations, and ergonomic improvements.

We encourage existing projects to upgrade to 1.0.0 when possible. We feel that the improvements it brings over 0.2.0 and previous releases are substantial!

Changes Since 0.2.0

  • Added Fragments, which reduces the need for many container instances. (#172)
  • Added Bindings, which enables easy surgical updates to instances without using refs. (#159)
  • Added opt-in runtime type checking across the entire Roact API. (#188)
  • Added support for prop validation akin to React's propTypes.
  • Changed Component:setState to be deferred if it's called while Roact is updating a component. (#183)
  • Changed events connected via Roact.Event and Roact.Change triggered by a Roact update to be deferred until Roact is done updating the instance.
  • Improved and consolidated terminology across the board.
  • Improved errors to be much more informative and clear.

Fragments

The Roact.createFragment API enables returning multiple components from the render function of a function or stateful component.

Where we would previously have to create dummy Folder instances or nest elements endlessly, we can now return a fragment containing multiple objects!

Before, in 0.2.0:

local function Connectors()
    return Roact.createElement("Folder", {
        Keyboard = Roact.createElement(KeyboardConnector),
        Mouse = Roact.createElement(MouseConnector),
    })
end

Now, in 1.0.0:

local function Connectors()
    return Roact.createFragment({
        Keyboard = Roact.createElement(KeyboardConnector),
        Mouse = Roact.createElement(MouseConnector),
    })
end

Bindings

Bindings are a great way to build animations, as well as a good way to improve performance in cases where Roact isn't quite keeping up.

Check out our brand new bindings and refs guide for an introduction to how bindings can be used.

Bindings can be used to create an efficient, safe, and performant Roact fit-to-contents implementation:

local FitList = Roact.Component:extend("FitList")

function FitList:init()
    self.size, self.setSize = Roact.createBinding(Vector2.new())
end

function FitList:render()
    local children = {
        Layout = Roact.createElement("UIListLayout", {
            [Roact.Change.AbsoluteContentSize] = function(instance)
                self.setSize(instance.AbsoluteContentSize)
            end,
        })
    }

    for key, child in pairs(self.props[Roact.Children]) do
        children[key] = child
    end

    return Roact.createElement("Frame", {
        Size = self.size:map(function(absoluteSize)
            return UDim2.new(0, absoluteSize.X, 0, absoluteSize.Y)
        end),
    }, children)
end

Prop Validation

Set the validateProps value on your stateful component class to enable opting into strong type checking every time props update.

Prop validation is opt-in! To enable it in your project, use Roact.setGlobalConfig once somewhere in your project:

Roact.setGlobalConfig({
    propValidation = true,
})

When paired with libraries like t by Osyris, it's easy to make sure your components are accepting the correct props:

local CoolTextLabel = Roact.Component:extend("CoolTextLabel")

CoolTextLabel.validateProps = t.strictInterface({
    text = t.string,
    layoutOrder = t.optional(t.integer),
})

function CoolTextLabel:render()
    return Roact.createElement("TextLabel", {
        Size = UDim2.new(0, 400, 0, 400),
        Text = self.props.text,
        LayoutOrder = self.props.layoutOrder,
    })
end

Improved Terminology & Errors

We have a huge new suite of documentation and error messages that should make everything more clear when you run into problems.