Skip to content

Commit

Permalink
random-number-range example
Browse files Browse the repository at this point in the history
  • Loading branch information
masenf committed Sep 27, 2023
1 parent 94dc9f8 commit 29d0013
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 0 deletions.
4 changes: 4 additions & 0 deletions random-number-range/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.db
*.py[cod]
.web
__pycache__/
Binary file added random-number-range/assets/favicon.ico
Binary file not shown.
Empty file.
148 changes: 148 additions & 0 deletions random-number-range/random_number_range/random_number_range.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
"""This example demonstrates two techniques for achieving a long running task:
Chained Events: each step of the event recursively queues itself to run again.
Background Tasks: a background task is started and runs until it is cancelled.
The background task is the newer approach and is generally preferrable because
it does not block UI interaction while it is running.
"""
import asyncio
import random
from typing import List

import reflex as rx


class BaseState(rx.State):
rrange: List[int] = [-10, 10]
delay: int = 1
_last_values: List[int] = []
total: int = 0

@rx.var
def last_values(self) -> str:
return ", ".join(str(x) for x in self._last_values[-10:])

def balance(self):
max_magnitude = max(abs(x) for x in self.rrange)
self.rrange = [-max_magnitude, max_magnitude]


class BackgroundState(BaseState):
running: bool = False
loading: bool = False
_n_tasks: int = 0

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

while True:
async with self:
self.loading = True

# Simulate long running API call
await asyncio.sleep(self.delay)

async with self:
last_value = random.randint(*self.rrange)
self.total += last_value
self._last_values = self._last_values[-9:] + [last_value]
self.loading = False
if not self.running:
break

async with self:
self._n_tasks -= 1

def set_running(self, value: bool):
self.running = value
if value:
return BackgroundState.run_task

def single_step(self):
self.running = False
return BackgroundState.run_task


class ChainState(BaseState):
running: bool = False
loading: bool = False

async def run_task(self):
self.loading = True
yield

# Simulate long running API call
await asyncio.sleep(self.delay)

last_value = random.randint(*self.rrange)
self.total += last_value
self._last_values = self._last_values[-9:] + [last_value]
self.loading = False

if self.running:
yield ChainState.run_task

def set_running(self, value: bool):
self.running = value
if self.running:
return ChainState.run_task

def single_step(self):
self.running = False
return ChainState.run_task


other_links = {
"Chain Events": lambda State: rx.link("Background Task Version", href="/background", on_click=State.set_running(False)),
"Background Task": lambda State: rx.link("Chain Event Version", href="/chain", on_click=State.set_running(False)),
}


def random_numbers_in_range(State, mode: str) -> rx.Component:
return rx.center(
rx.vstack(
rx.heading(f"Random Numbers in Range"),
rx.heading(f"{mode} version", font_size="1.5em"),
other_links[mode](State),
rx.hstack(
rx.text("Min: ", State.rrange[0], padding_right="3em"),
rx.button("Balance", on_click=State.balance),
rx.text("Max: ", State.rrange[1], padding_left="3em"),
),
rx.range_slider(value=State.rrange, on_change=State.set_rrange, min_=-100, max_=100),
rx.hstack(
rx.text("Last 10 values: ", State.last_values),
rx.cond(State.loading, rx.spinner()),
),
rx.hstack(
rx.text("Total: ", State.total),
rx.button("Clear", on_click=lambda: State.set_total(0)),
),
rx.hstack(
rx.vstack(
rx.text("Run", font_size="0.7em"),
rx.switch(is_checked=State.running, on_change=State.set_running),
),
rx.vstack(
rx.text("Delay (sec)", font_size="0.7em"),
rx.select(*[rx.option(x) for x in range(1, 5)], value=State.delay.to(str), on_change=State.set_delay),
padding_right="3em",
),
rx.button("Single Step", on_click=State.single_step),
align_items="flex-start",
),
width="50vw",
),
)


app = rx.App()
app.add_page(rx.fragment(on_mount=rx.redirect("/chain")), route="/")
app.add_page(random_numbers_in_range(ChainState, "Chain Events"), route="/chain")
app.add_page(random_numbers_in_range(BackgroundState, "Background Task"), route="/background")
app.compile()
1 change: 1 addition & 0 deletions random-number-range/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
reflex>=0.2.8
5 changes: 5 additions & 0 deletions random-number-range/rxconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import reflex as rx

config = rx.Config(
app_name="random_number_range",
)

0 comments on commit 29d0013

Please sign in to comment.