Stipple.jl
Stipple.jl copied to clipboard
0.25.20 breaks asynchronous tasks in reactive code blocks
I have this code that runs a @task in which a counter gets increased each second. It worked in 0.25.15, but after upgrading to 0.20.20 it stops working.
using GenieFramework
@genietools
@handlers begin
p = @task 1+1
@in x = 0.00
@onchange isready begin
if !istaskstarted(p) || istaskdone(p)
p = @task begin
println("Task started")
while x <= 100
x = x + 1
sleep(1)
end
end
schedule(p)
end
end
end
function ui()
bignumber("Counter", :x)
end
@page("/", ui)
Server.isrunning() || Server.up()
this is the error I'm getting on 0.20.25 and Julia 1.8.5
┌ Error: 2023-02-15 20:56:50 Error attempting to invoke handler 3 for field Reactive{Bool}(Observable(true), 1, false, false, "") with value true
└ @ Stipple ~/.julia/packages/Stipple/Ird4L/src/stipple/mutators.jl:36
┌ Error: 2023-02-15 20:56:50 UndefVarError(:p)
└ @ Stipple ~/.julia/packages/Stipple/Ird4L/src/stipple/mutators.jl:37
I think @hhaensel can look at it. Can you check if it work on master with changes helmut made for kw. Not sure I understand the error
I know what happened. You are using a local variable in handlers which I had not thought of when I generalised the Reactive API. I shall address this in a future release. Meanwhile an easy work around is to define a private field instead of a local variable:
@app begin
@private p = @task 1+1
@in x = 0.00
@onchange isready begin
if !istaskstarted(p) || istaskdone(p)
p = @task begin
println("Task started")
while x <= 100
x = x + 1
sleep(1)
end
end
schedule(p)
end
end
end
Note, that I have used @appinstead of @handlers which clears the variable cache, so that you can rename variables without having old names trailing in the model.
I also enhanced @handlers so that you can also declare non_reactive fields:
@app begin
@private non_reactive p = @task 1+1
@in x = 0.00
@onchange isready begin
if !istaskstarted(p) || istaskdone(p)
p = @task begin
println("Task started")
while x <= 100
x = x + 1
sleep(1)
end
end
schedule(p)
end
end
end
Should the official recommendation (and demos) be to always use @app instead of @handlers? Or why don't we replace @app with @handlers at code level so all codebases get automatically migrated to the @app features?
I explained in detail in #159.
In my eyes @app is the new standard, it combines both field and handler definition and clears both storages before setting the new values.
If you are adapting old code the quickest way is to replace the old @reactive statement with the respective @vars statement and to define handlers separately by @handlers, which then does not clear the REACTIVE_STORAGE, e.g. from
@reactive! mutable struct TreeDemo <: ReactiveModel
d::R{Dict{String, Any}} = deepcopy(testdict)
tree::R{Vector{Dict{Symbol, Any}}} = [dict_tree(testdict)]
tree_selected::R{String} = ""
tree_ticked::R{Vector{String}} = String[]
tree_expanded::R{Vector{String}} = String[]
end
function handlers(model)
on(model.isready) do isready
isready && push!(model)
end
model
end
to
@appname TreeDemo
@vars begin
d = deepcopy(testdict)
tree = [dict_tree(testdict)]
tree_selected = ""
tree_ticked = String[]
tree_expanded = String[]
end
@handlers
onchange isready begin
isready && @push
end
end
@hhaensel did you make any change about this? Are variables non-reactive by default now?