Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incremental state updates resend entire state #4156

Open
dodslaser opened this issue Oct 11, 2024 · 2 comments
Open

Incremental state updates resend entire state #4156

dodslaser opened this issue Oct 11, 2024 · 2 comments
Labels
enhancement Anything you want improved

Comments

@dodslaser
Copy link

dodslaser commented Oct 11, 2024

Describe the bug
I'm trying to adapt some of the example code in the docs to fit my needs. Essentially, I want to live-stream text line by line into a code block. From what I've understood, I should be able to append to a state variable (a list) in a background handler, and use yield each time a new line is added to send the state changes incrementally to the frontend.

When I try this approach, each time state is updated, the full state is sent to the frontend, including the previously sent lines (as part of the 'delta' section in the JSON). From what I understood, only the newly added (or removed) lines should be sent (i.e. incremental updates).

In my full scale application, I would potentially be appending to a list of thousands or more lines. It would pretty quickly get out of hand if the whole state had to be sent each time. Am I missing something obvious here? Is there a better way of achieving this?

To Reproduce

import reflex as rx
import asyncio as aio

class LiveState(rx.State):
    data: list[str] = []
    _counter: int = 0
    _n_tasks: int = 0

    @rx.background
    async def update_data(self):
        async with self:
            if self._n_tasks > 0:
                return
            self._n_tasks += 1

        while True:
            async with self:
                self.data.append(f"Message #{self._counter}")
                self._counter += 1
                yield
            await aio.sleep(1)

@rx.page(on_load=LiveState.update_data)
def index():
    return rx.code_block(LiveState.data.join("\n"))

Expected behavior
Only the changes in state are sent, not the whole thing.

Specifics (please complete the following information):

  • Python Version: 3.12
  • Reflex Version: 0.6.1
  • OS: macOS Sequoia 15.0 (M1 Max)
  • Browser (Optional): Firefox 131.02
@dodslaser dodslaser added the bug Something isn't working label Oct 11, 2024
@masenf
Copy link
Collaborator

masenf commented Oct 11, 2024

we have a backlog item to implement https://datatracker.ietf.org/doc/html/rfc6902, but the behavior you are currently seeing is expected. reflex does not send the full state, only the vars that have changed... but if the var that has changed is already very large, then yes, it does send the complete value over.

@adhami3310 adhami3310 added enhancement Anything you want improved and removed bug Something isn't working labels Oct 14, 2024
@dodslaser
Copy link
Author

Ah, ok, that makes sense. JSON Patch would definitely be neat. In the meantime I'll probably solve this with WebSockets and custom components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Anything you want improved
Projects
None yet
Development

No branches or pull requests

3 participants