Description
Component
Reactive Programming
Severity
P2 - Medium (workaround exists)
Shiny Version
1.3.0
Python Version
3.11.1
Minimal Reproducible Example
from shiny import App, reactive, render, ui
app_ui = ui.page_fluid(
ui.input_action_button("add", "add"),
ui.input_action_button("remove", "remove"),
ui.output_text("info")
)
def server(input, output, session):
check = reactive.value([0])
@reactive.effect()
@reactive.event(input.add)
def _():
check.set(check() + [input.add()])
@reactive.effect()
@reactive.event(input.remove)
def _():
x = check()
_ = x.pop()
print(x)
check.set(x)
print(check())
@render.text
def info():
return f"The value is {check()}"
app = App(app_ui, server)
Behavior
Add function works as expected
In the example above, clicking the add
button will add a number to the list and the text output will update as expected.
Remove function unexpected effect
When clicking the remove
button, the reactive variable is updated (see console output), but nothing is triggered so the UI won't update until another process like the add
button shows the new output.
Explanation
The reason is that x = check()
is not making a copy of the reactive value, but just transferring the ownership, which is normal python behaviour. However, the fact that it is then possible to actually update the reactive variable but not evoking a trigger, is unexpected and counterintuitive. I suggest this should either result in an error, or propagate as expected.
When using x = check().clone()
instead, the app works as expected. Again, I would argue this is the correct syntax, but the shown alternative should not allow to silently change the reactive variable without a trigger.
Error Messages (if any)
Environment
Windows 10
Chrome