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

New rec document fragments #176

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* Ref switching now occurs in one pass, which should fix edge cases where the result of a ref is `nil`, especially in property changed events ([#98](https://github.com/Roblox/roact/pull/98))
* `setState` can now be called inside `init` and `willUpdate`. Instead of triggering a new render, it will affect the currently scheduled one. ([#139](https://github.com/Roblox/roact/pull/139))
* Roll back changes that allowed `setState` to be called inside `willUpdate`, which created state update scenarios with difficult-to-determine behavior. ([#157](https://github.com/Roblox/roact/pull/157))
* Add fragment support via `Roact.createFragment` ([#172](https://github.com/Roblox/roact/pull/172))

## 1.0.0 Prerelease 2 (March 22, 2018)
* Removed `is*Element` methods, this is unlikely to affect anyone ([#50](https://github.com/Roblox/roact/pull/50))
Expand Down
68 changes: 68 additions & 0 deletions docs/advanced/fragments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Fragments are a tool for avoiding unnecessary nesting when organizing components by allowing components to render collections of elements without wrapping them in a single containing element.

## Without Fragments

Typically, Roact components will render a single element via `createElement`. For example, suppose we define a component like this:
```lua
local function TeamList(props)
return Roact.createElement("Frame", {
-- Props for Frame...
}, {
Layout = Roact.createElement("UIListLayout", {
-- Props for UIListLayout...
})
ListItems = Roact.createElement(TeamLabels)
})
end
```

Suppose we also want to use a separate component to render a collection of `TextLabel`s:
```lua
local function TeamLabels(props)
return Roact.createElement("Frame", {
-- Props for Frame...
}, {
RedTeam = Roact.createElement("TextLabel", {
-- Props for item...
}),
BlueTeam = Roact.createElement("TextLabel", {
-- Props for item...
})
})
end
```

Unfortunately, the `TeamLabels` component can't return two different labels without wrapping them in a containing frame. The resulting Roblox hierarchy from these `TeamList` component won't actually apply the `UIListLayout` to the list of items, because it's grouped incorrectly:
```
Frame:
UIListLayout
Frame:
TextLabel
TextLabel
```

## With Fragments

In order to separate our list contents from our list container, we need to be able to return a group of elements from our render method rather than a single one. Fragments make this possible:
```lua hl_lines="2"
local function TeamLabels(props)
return Roact.createFragment({
RedTeam = Roact.createElement("TextLabel", {
-- Props for item...
}),
BlueTeam = Roact.createElement("TextLabel", {
-- Props for item...
})
})
end
```

We provide `Roact.createFragment` with a table of elements. These elements will result in multiple children of this component's parent. When used in combination with the above `TeamList` component, it will generate the desired Roblox hierarchy:
```
Frame:
UIListLayout
TextLabel
TextLabel
```

We are also free to create alternate views that use the same `TeamLabels` component with different Layouts or groupings.
12 changes: 11 additions & 1 deletion docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ The `children` argument is shorthand for adding a `Roact.Children` key to `props
`component` can be a string, a function, or a table created by `Component:extend`.

!!! caution
Once `props` or `children` are passed into the `createElement`, make sure not to modify them!
Make sure not to modify `props` or `children` after they're passed into `createElement`!

### Roact.createFragment
```
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
```
Expand Down
1 change: 1 addition & 0 deletions lib/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ local reconcilerCompat = createReconcilerCompat(robloxReconciler)
local Roact = strict {
Component = require(script.Component),
createElement = require(script.createElement),
createFragment = require(script.createFragment),
oneChild = require(script.oneChild),
PureComponent = require(script.PureComponent),
None = require(script.None),
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pages:
- State and Lifecycle: guide/state-and-lifecycle.md
- Events: guide/events.md
- Advanced Concepts:
- Fragments: advanced/fragments.md
- Portals: advanced/portals.md
- Refs: advanced/refs.md
- Context: advanced/context.md
Expand Down