reflex icon indicating copy to clipboard operation
reflex copied to clipboard

feat: PoC for shared states.

Open abulvenz opened this issue 1 year ago β€’ 0 comments

Fixes https://github.com/reflex-dev/reflex/issues/2771 in a prototypical way.

Note class News(State, scope=State.topic): in example below. What is working so far: Open two tabs:

  • change "Title" to whatever and click "Post"
  • change "Title" in other tab and post.
  • See the entire state.

TODOs:

  • [X] manage subscriptions to socket.io rooms based on scope vars
  • [X] emit updates to socket.io rooms
  • [X] make it work with redis
  • [ ] Initial subscriptions and state loading
  • [ ] redis pubsub
  • [ ] To use lists as scope, e.g. use case when subscribing to multiple channels at the same time, dynamic states of @benedikt-bartscher are needed https://github.com/reflex-dev/reflex/pull/3671
import reflex as rx

app = rx.App()

class Article(rx.Base):
    title: str = "Title"
    content: str = "Content"

    def __str__(self):
        return f"{self.title}: {self.content}"

class State(rx.State):
    message: str = "Default"
    catalog: dict[str, str] = {"key": "value"}

    topic: str = "General"

    def printum(self):
        for key in app.state_manager.states.keys():
            print(key.split("_")[0])


class News(State, scope=State.topic):

    news: list[Article] = []

    def post(self, article: Article):
        print(f"Posting article {article}")
        self.news.append(article)


class NewNews(rx.State):
    draft: Article = Article()

    def set_title(self, title: str):
        self.draft.title = title

    def set_content(self, content: str):
        self.draft.content = content

def render_news(article: Article) -> rx.Component:
    return rx.box(
        rx.heading(article.title),
        rx.text(article.content),
    )

def index() -> rx.Component:
    return rx.container(
        rx.input(value=State.topic, on_change=State.setvar("topic")),
        rx.foreach(News.news, render_news),
        rx.input(value=NewNews.draft.title, on_change=NewNews.set_title),
        rx.input(value=NewNews.draft.content, on_change=NewNews.set_content),
        rx.button("Post", on_click=lambda :News.post(NewNews.draft)),
        rx.button("Printum", on_click=State.printum),
    )

app.add_page(index)

abulvenz avatar Jul 16 '24 20:07 abulvenz