rx.debounce_input() does not work with rx.slider()
Describe the bug
When using a controlled rx.slider(), I want the on_change handler to be de-bounced, to have both:
- a responsive UI
- protect the backend from spam
I have tried using on_value_commit, but it is pretty flakey. See Radix UI issue: https://github.com/radix-ui/primitives/issues/1760
Instead, I opted to try rx.debounced_input(), but it is not compatible with rx.slider().
I suspect debounce_input() is intended to work with semantic <input> HTML elements, but Radix UI opted for their own funky implementation (a bunch of span/p/divs). π€·ββοΈ
To Reproduce Steps to reproduce the behavior:
value = State.my_values[name]
min_val = 0
max_val = 100
rx.debounce_input(
rx.slider(
value=[value],
on_change=lambda val: State.update_my_value(name, val, True),
min=min_val,
max=max_val,
step=1,
),
debounce_timeout=2_000,
)
If I specify a value on rx.slider(), I get:
TypeError: Invalid var passed for prop value, expected type <class 'str'>, got value [state__state.my_values[name]] of type <class 'list'>.
If I omit it, I get a react compilation error:
Unhandled Runtime Error
TypeError: (intermediate value).map is not a function
Call Stack
Slider<
node_modules/@radix-ui/themes/dist/esm/components/slider.js (14:0)
renderWithHooks
node_modules/react-dom/cjs/react-dom.development.js (16305:0)
updateForwardRef
node_modules/react-dom/cjs/react-dom.development.js (19226:0)
beginWork
node_modules/react-dom/cjs/react-dom.development.js (21636:0)
callCallback
node_modules/react-dom/cjs/react-dom.development.js (4164:0)
invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js (4213:0)
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js (4277:0)
beginWork$1
node_modules/react-dom/cjs/react-dom.development.js (27451:0)
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js (26557:0)
workLoopSync
node_modules/react-dom/cjs/react-dom.development.js (26466:0)
renderRootSync
node_modules/react-dom/cjs/react-dom.development.js (26434:0)
performConcurrentWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js (25738:0)
workLoop
node_modules/scheduler/cjs/scheduler.development.js (266:0)
flushWork
node_modules/scheduler/cjs/scheduler.development.js (239:0)
performWorkUntilDeadline
node_modules/scheduler/cjs/scheduler.development.js (533:0)
Expected behavior Either:
-
on_value_commitis not flakey -
debounce_inputworks with a slider
Specifics (please complete the following information):
- Python Version: 3.10
- Reflex Version: 0.4.5
- OS: MacOS
- Browser (Optional): Firefox
There are two problems going on here:
- the type of
valueinDebounceInputisVar[str], and it should beVar[Any]so that any underlying API can be used - The other problem was below that:
Reflex actually renames the prop onChange to onValueChange for the radix Slider element, but the debounce doesn't take this into account, and so it never actually gets the sliders onValueChange event fired and thus never updates. This is actually much harder to fix...
On the plus side, we are considering adding a reflex native "event throttling" mechanism. Similar to debounce, but actually to rate limit the number of events sent to the backend in a given time interval. We don't have a firm date for when such a feature will be available though.
I don't see an easy fix or workaround for this at the moment.
Thanks for the quick answer!
I haven't tried implementing a custom UI component in Reflex yet, but could a valid workaround (assuming the 1st point you mention gets fixed) be to implement my own <input type="range"> based component, and wrap it in a debounce_input()?
EDIT: although that might also be problematic without using raw rx.html(), as rx.input() seems to assume a textual input (as it adds classes like rt-TextFieldInput etc.).
EDIT: although that might also be problematic without using raw
rx.html(), asrx.input()seems to assume a textual input (as it adds classes likert-TextFieldInputetc.).
We also have the el namespace for basic HTML element, so you can maybe extend from rx.el.input instead