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

Commit

Permalink
Rewrite Ref page in advanced guide (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
LPGhatguy committed Jul 31, 2018
1 parent 2e2d9df commit d718e62
Showing 1 changed file with 47 additions and 48 deletions.
95 changes: 47 additions & 48 deletions docs/advanced/refs.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,68 @@
*Refs* grant access to the actual Instance objects that are created by Roact. They're an escape hatch for when something is difficult or impossible to correctly express with the Roact API.
*Refs* grant access to the Roblox Instance objects that are created by Roact. They're an escape hatch for when something is difficult or impossible to correctly express with the Roact API.

!!! info
Refs can only be used with primitive components.
Refs are intended to be used in cases where Roact cannot solve a problem directly, or its solution might not be performant enough, like:

## Refs in Action
To create a ref, pass a function prop with the key `Roact.Ref` when creating a primitive element.
* Resizing a box to fit its contents dynamically
* Gamepad selection
* Animations

Refs can only be attached to primitive components. This is different than React, where refs can be used to call members of composite components.

For example, suppose we wanted to create a search bar that captured cursor focus when any part of it was clicked. We might use a component like this:
## Refs in Action
To use a ref, call `Roact.createRef()` and put the result somewhere persistent. Generally, that means that refs are only used inside stateful components.

```lua
--[[
A search bar with an icon and a text box that captures focus for its TextBox
when its icon is clicked
]]
local SearchBar = Roact.Component:extend("SearchBar")
local Foo = Roact.Component:extend("Foo")

function SearchBar:init()
function Foo:init()
self.textBoxRef = Roact.createRef()
end
```

function SearchBar:render()
-- Render our icon and text box side by side in a Frame
return Roact.createElement("Frame", {
Size = UDim2.new(0, 200, 0, 20),
}, {
SearchIcon = Roact.createElement("ImageButton", {
Size = UDim2.new(0, 20, 0, 20),

-- Handle click events on the icon
[Roact.Event.Activated] = function()
self.textBoxRef.current:CaptureFocus()
end
}),

SearchTextBox = Roact.createElement("TextBox", {
Size = UDim2.new(0, 180, 0, 20),
Position = UDim2.new(0, 20, 0, 0),
Next, use the ref inside of `render` by creating a primitive component. Refs use the special key `Roact.Ref`.

-- Use Roact.Ref to get a reference to the underlying object
[Roact.Ref] = self.textBoxRef
}),
```lua
function Foo:render()
return Roact.createElement("TextBox", {
[Roact.Ref] = self.textBoxRef,
})
end
```
When a user clicks on the outer `ImageButton`, the `captureTextboxFocus` callback will be triggered and the `TextBox` instance will get focus as if it had been clicked on directly.

## Refs During Unmount

!!! warning
When using the function version of refs, any time a component instance is destroyed or the ref property changes, `nil` will be passed to the old ref function!
Finally, we can use the value of the ref at any point after our component is mounted.

```lua
local frame = Roact.createElement("Frame", {
[Roact.Ref] = function(rbx)
print("Ref was called with", rbx, "of type", typeof(rbx))
end
})
function Foo:didMount()
-- The actual Instance is stored in the 'current' property of a ref object.
local textBox = self.textBoxRef.current

local handle = Roact.mount(frame)
print("TextBox has this text:", textBox.Text)
end
```

-- Output:
-- Ref was called with Frame of type Instance
## Function Refs
The original ref API was based on functions instead of objects. Its use is not recommended for most cases anymore, but it can still be useful in some cases.

Roact.unmount(handle)
This style of ref involves passing a function as the `Roact.Ref` prop as opposed to a dedicated ref object:

-- In the output:
-- Ref was called with nil of type nil
```lua
local function Bar(props)
return Roact.createElement("TextBox", {
[Roact.Ref] = function(instance)
-- Be careful to guard against nil refs; this is a gotcha of
-- function refs.
if instance ~= nil then
print("TextBox has this text:", instance.Text)
else
print("TextBox ref removed.")
end
end,
})
end
```

!!! warning
When a function ref is called, it's not guaranteed that its sibling or parent components have finished mounting. Causing side effects here can cause difficult-to-trace bugs.

!!! warning
When a component with a function ref unmounts, or when the ref value changes, the component's ref is passed `nil`.

0 comments on commit d718e62

Please sign in to comment.