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

[WIP] (docs): update docs/performance/reduce-reconcilation.md #317

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
14 changes: 9 additions & 5 deletions docs/performance/reduce-reconciliation.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ In all likelihood, the primary source of performance gains for your app will com

## `shouldUpdate` Lifecycle Method
When a Roact Component's state or props change, it will call the Component's `shouldUpdate` method to determine whether or not to re-render it. The default implementation will always return true.

```lua
function Component:shouldUpdate(newProps, newState)
return true
end
```

If you have a more complex component that only needs to re-render in certain situations, you can either use `PureComponent` (discussed below) or implement your own `shouldUpdate` and return `false` in any case where an update is not required.
Suppose you have a more complex component that only needs to re-render in certain situations. In that case, you can either use `PureComponent` (discussed below) or implement your own `shouldUpdate` and return `false` in any case where an update is not required.

!!! warning
Manually implementing `shouldUpdate` is *dangerous*! If done carelessly, it can easily create confusing or subtle bugs.
Expand All @@ -22,6 +23,7 @@ If you have a more complex component that only needs to re-render in certain sit
One common implementation of `shouldUpdate` is to do a shallow comparison between current and previous props and state. `Roact` provides an extension of `Roact.Component` called `Roact.PureComponent` that uses this implementation.

Let's use the following example:

```lua
local Item = Roact.Component:extend("Item")

Expand Down Expand Up @@ -61,12 +63,12 @@ function Inventory:render()
Size = UDim2.new(0, 200, 0, 400)
}, itemList)
end

```

In the above example, adding a new item to the `items` prop of the `Inventory` would cause all of the child `Item` elements to re-render, even if they haven't changed at all. This means if you add an item to an `Inventory` that already has 5 items, the result will be 6 renders of the `Item` component.

Lets change `Item` to a `PureComponent`:

```lua
local Item = Roact.PureComponent:extend("Item")
```
Expand All @@ -82,9 +84,10 @@ Now, if we add a new item to the end of the `Inventory` or change something abou

Another performance improvement we can make is to use stable, unique keys to refer to our child elements.

When the list that we pass into the `Inventory` component changes, Roact updates our Roblox UI by adjusting the properties of each Roblox Instance according to the new list of elements.
For example, suppose a list we pass into the `Inventory` component changes. Roact would update the Roblox UI by adjusting the properties of each Roblox Instance according to the new list of elements.

For example, let's suppose our list of items is as follows:

```lua
{
{ id = "sword", icon = swordIcon }, -- [1]
Expand All @@ -93,6 +96,7 @@ For example, let's suppose our list of items is as follows:
```

If we add a new item to the beginning, then we'll end up with a list like this:

```lua
{
{ id = "potion", icon = potionIcon } -- [1]
Expand All @@ -103,7 +107,7 @@ If we add a new item to the beginning, then we'll end up with a list like this:

When Roact updates the underlying `ImageLabel` objects, it will need to change their icons so that the item at `[1]` has the potion icon, the item at `[2]` has the sword icon, and a new `ImageLabel` is added at `[3]` with the shield icon.

We'd like for Roact to know that the new item was added at `[1]` and that the sword and shield items simply moved down in the list. That way it can adjust their LayoutOrder properties and let the Roblox UI system resolve the rest.
We want Roact to know that the new item was added at `[1]` and that the sword and shield items moved down in the list. That way, it can adjust their LayoutOrder properties and let the Roblox UI system resolve the rest.

So let's fix it! We'll make our list of `Item` elements use the item's id for its keys instead of the indexes in the `items` list:

Expand Down Expand Up @@ -132,7 +136,7 @@ function Inventory:render()
end
```

Now the list of children is keyed by the stable, unique id of the item data. Their positions can change according to their LayoutOrder, but no other properties on the item need to be updated. When we add the third element to the list, Roact will set the `LayoutOrder` property on for each `ImageLabel` and only set the `Image` property on the newly added one!
Now the list of children is keyed by the stable, unique id of the item data. Their positions can change according to their LayoutOrder, but no other item properties need to be updated. When we add the third element to the list, Roact will set the `LayoutOrder` property on each `ImageLabel` and only set the `Image` property on the newly added one!

!!! info
Switching to static keys might seem insignificant for *this* example, but if our `Item` component becomes more complicated and our inventory gets bigger, it can make a significant difference!