Fetch Data From Server
This code shows how to deal with yielding/blocking code, such as fetching data from a server.
Because these tasks don't complete immediately, they can't be directly run
inside of a Computed
, so this example provides a robust framework for handling
this in a way that doesn't corrupt your code.
This example assumes the presence of a Roblox-like task
scheduler.
Overview¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
Explanation¶
If you yield or wait inside of a Computed
, you can easily corrupt your entire
program.
However, this example has a function, fetchUserBio
, that yields.
local function fetchUserBio(
userID: number
): string
-- pretend this calls out to a server somewhere, causing this code to yield
task.wait(1)
return "This is the bio for user " .. userID .. "!"
end
It also has some arbitrary state object, currentUserID
, that it needs to
convert into a bio somehow.
-- This doesn't have to be a `Value` - any kind of state object works too.
local currentUserID = scope:Value(1670764)
Because Computed
can't yield, this code has to manually manage a
currentUserBio
object, which will store the output of the code in a way that
can be used by other Fusion objects later.
Notice that the 'loading' state is explicitly documented. It's a good idea to be clear and honest when you have no data to show, because it allows other code to respond to that case flexibly.
-- While the bio is loading, this is `nil` instead of a string.
local currentUserBio: Fusion.Value<string?> = scope:Value(nil)
To perform the actual fetch, a simple function can be written which calls
fetchUserBio
in a separate task. Once it returns a bio, the currentUserBio
can be updated.
To avoid two fetches overwriting each other, any existing fetch task is canceled before the new task is created.
local fetchInProgress = nil
local function performFetch()
local userID = peek(currentUserID)
currentUserBio:set(nil)
if fetchInProgress ~= nil then
task.cancel(fetchInProgress)
end
fetchInProgress = task.spawn(function()
currentUserBio:set(fetchUserBio())
fetchInProgress = nil
end)
end
Finally, to run this function when the currentUserID
changes, performFetch
can be added to an Observer
.
The onBind
method also runs performFetch
once at the start of the program,
so the request is sent out automatically.
scope:Observer(currentUserID):onBind(performFetch)
That's all you need - now, any other Fusion code can read and depend upon
currentUserBio
as if it were any other kind of state object. Just remember to
handle the 'loading' state as well as the successful state.
scope:Observer(currentUserBio):onBind(function()
local bio = peek(currentUserBio)
if bio == nil then
print("User bio is loading...")
else
print("Loaded user bio:", bio)
end
end)
You may wish to expand this code with error handling if fetchUserBio()
can
throw errors.