High-performance scrolling lists ported from React Native for react-lua.
A collection of virtual list components, supporting the most handy features:
- Fully cross-platform
- Optional horizontal mode
- Configurable viewability callbacks
- Header support
- Footer support
- Separator support
- Pull to Refresh
- Scroll loading
- ScrollToIndex support
- Multiple column support
- Animation suppot
Virtualization massively improves memory consumption and performance of large lists by maintaining a finite render window of active items and replacing all items outside of the render window with appropriately sized blank space. The window adapts to scrolling behavior, and items are rendered incrementally with low-priority (after any running interaction responses) if they are far from the visible area, or with high-priority otherwise to minimize the potential of seeing blank space.
Virtualized lists aren't appropriate for all situations. Here's some caveats:
- Internal state is not preserved when content scrolls out of the render window. Make sure all your data is captured in the item data or an external store like Rodux.
- Everything is a
PureComponent
, which means that it will not re-render ifprops
are shallow-equal. Make sure that everything yourrenderItem
function depends on is passed as a prop (e.g.extraData
) that is not shallow-equal after updates, otherwise your UI may not update on changes. This includes thedata
prop and parent component state. - In order to constrain memory and enable smooth scrolling, content is rendered asynchronously offscreen. This means it's possible to scroll faster than the fill rate and momentarily see blank content. This is a tradeoff that can be adjusted to suit the needs of each application.
- By default, the lists look for a
key
prop on each item and uses that for the React key. Alternatively, you can provide a customkeyExtractor
prop.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HttpService = game:GetService("HttpService")
local Players = game:GetService("Players")
local Packages = ReplicatedStorage.Packages
local React = require(Packages.React)
local ReactRoblox = require(Packages.ReactRoblox)
local VirtualizedList = require(Packages.VirtualizedList)
local View = VirtualizedList.View
local FlatList = VirtualizedList.FlatList
local e = React.createElement
local ITEM_COUNT = 10_000
local DATA = table.create(ITEM_COUNT)
for i = 1, ITEM_COUNT do
DATA[i] = {
id = HttpService:GenerateGUID(false),
title = `Item {i}`,
}
end
local function Item(props)
return e(View, {}, {
ItemText = e("TextLabel", {
Size = UDim2.new(1, 0, 0, 40),
Text = props.title,
}),
})
end
local function App()
return e("ScreenGui", {
ResetOnSpawn = false,
ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
}, {
Background = e("Frame", {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.fromScale(0.25, 0.4),
}, {
List = e(FlatList, {
data = DATA,
renderItem = function(entry)
return e(Item, {
title = entry.item.title,
})
end,
keyExtractor = function(entry)
return entry.id
end,
}),
}),
})
end
local root = ReactRoblox.createRoot(Instance.new("Folder"))
root:render(ReactRoblox.createPortal(e(App), Players.LocalPlayer.PlayerGui))
These components are directly ported from React Native 0.68, so most documentation and articles should apply (modulo Lua syntax). More information on the provided list components can be found at:
VirtualizedList
- https://reactnative.dev/docs/virtualizedlistFlatList
- https://reactnative.dev/docs/flatlistSectionList
- https://reactnative.dev/docs/sectionlist
- Add unit tests from upstream React Native
- Use
darklua
bundler to allow more files to easily run outside of Roblox - Add performance benchmarks