Answer to the Core Question
As of Reflex 1.x, the framework’s internal batching of state changes is hard‑wired to the JavaScript event‑loop tick. There is no public setting to adjust the timeout, change the maximum batch size, or disable batching for a particular handler or async callback. Likewise, Reflex does not expose a manual flush() API that forces pending updates to be sent over the WebSocket immediately.
Why the Design Is Fixed
- State pushes are coalesced to guarantee that all mutations made during a logical user interaction are delivered together, preventing split messages that could leave the client in an inconsistent state.
- Exposing a configurable window would risk breaking this invariant across releases, as the exact criteria for a batch are internal and may evolve.
- The current implementation relies on the JavaScript event loop: every call to
state.update() is queued, and the WebSocket push is emitted once the current tick completes.
Practical Guidance for Developers
Although you cannot change the batching window, you can still control when updates are sent by structuring your code:
- Group synchronous updates. Call
state.update() multiple times within the same event‑handler; all will be bundled into a single push.
- Await asynchronous work. If you need to perform async callbacks before sending the state,
await them inside the handler. This keeps the updates in the same event‑loop tick.
async def on_click(self, state: State):
# synchronous mutation
state.counter += 1
# async work
await some_async_operation()
# final mutation – still part of the same batch
state.status = "ready"
- Yield to the loop manually. If you must launch a background task that should not be part of the current batch, schedule it with
asyncio.create_task() *after* all synchronous mutations. Those mutations will be sent first; the task’s later mutation will be batched separately.
- Force a flush via a custom helper (experimental). Some developers patch the internal
_flush method of the State object to send the current buffer immediately. This is not officially supported and may break in future releases.
When a Manual Flush Might Be Needed
Typical use cases that would benefit from an explicit flush are:
- Sending a critical update before performing a long‑running async operation that could otherwise delay the push.
- Ensuring that a series of state changes triggered by a single user action are not split across multiple WebSocket frames.
Until a public API is introduced, the safest approach is to keep all related mutations within the same handler or await the async work before returning.
Next Steps & Diagnostic Detail
If you are working with a version of Reflex older than 1.2, the internal batching logic may differ slightly. Knowing the exact release you are on can help confirm whether any experimental hooks exist. Please let us know your reflex package version if you run into unexpected behavior.