Introduction
The reactive system is based on two primitive objects:- signals, which store a reactive value,
- and computation nodes, which store a reactive function.
- Widgets are created alongside a signal for their value.
- Cells are implicitly wrapped up in computation nodes.
- When a cell runs, it may access a widget value through the signal. If it does, the signal records that the cell’s computation node needs to rerun when the value changes.
- User input causes the UI to send an update to the kernel, which updates the widget value signal, which reruns all of its subscribers.
Custom Signals
Signals can be created at any time, independent of any widgets..sample()
allows reading a signal value without subscribing to its changes:
Reactive Transactions
Signal updates are delayed until the current cell finishes running all the way through:value
and value_str
are obviously related. The delayed updates ensure that the relationship is preserved at all times—cell 2 will never trigger an AssertionError
.
Contrast this with a hypothetical system that applies updates immediately.
cell_print 30 2
, cell_print 11 40
; which could be printed in an immediate-update system.
Reactivivity with Conditionals
Each time a cell reruns, it starts from a fresh state and will forget all its previous subscriptions. This means that a cell is only subscribed to the signals it access during its last run. Cells with conditionals can change their subscriptions on each run:value
changes to 50
, the cell will execute the conditional and thus access and subscirbe to value_str
.
If necessary, the cell can always uncoditionally subscribe to a signal by just accessing its value and not using it:
Redefining Signals
In Python, setting a variable will dispose of the old value entirely:del
:
locals()
:
Cheatsheet
x = Signal(initial)
defines a new signal with value set toinitial
x()
reads the value of the signal and subscribesx(10)
sets the value of the signalx.sample()
reads the value of the signal without subscribing. Useful to avoid infinite update loops- Signal updates are delayed until the current transactions ends
- Each time, all updated cells execute in one transaction
- Cells only subscribe to signals they accessed during the last run
- Signal values should be treated as immutable
- Re-assigning a signal to a global variable will override the value but not clear subscribers