跳到主要内容

Vars

Base Vars

变量是 app 中随时间可能发生变化的任何字段。变量直接呈现在应用程序的前端。

Base vars are defined as fields in your State class.

它们可以具有预设的默认值。如果您不提供默认值,则必须提供类型注释

class TickerState(rx.State):
ticker: str = "AAPL"
price: str = "$150"


def ticker_example():
return rx.center(
rx.vstack(
rx.heading(TickerState.ticker, size="3"),
rx.text(
f"Current Price: {TickerState.price}",
font_size="md",
),
rx.text("Change: 4%", color="green"),
),
)

Vars must be JSON serializable.

Accessing state variables on different pages

访问不同页面上的状态变量

状态只是一个 Python 类,因此可以在一页上定义,然后在另一页上导入并使用。在下面我们在页面 state.py 上定义 TickerState 类,然后在页面 index.py 上导入并使用它。

# state.py


class TickerState(rx.State):
ticker: str = "AAPL"
price: str = "$150"
# index.py
from .state import TickerState


def ticker_example():
return rx.center(
rx.vstack(
rx.heading(TickerState.ticker, size="3"),
rx.text(
f"Current Price: reflex___state____state__flexdown___modules____a4e3de79f19b87b4f4fce3d5f729c6b6b225d8d968533932d2e49adf411f2694____ticker_state.price",
font_size="md",
),
rx.text("Change: 4%", color="green"),
),
)

Backend-only Vars

任何以下划线开头的状态类中的变量都被视为仅后端使用,不会与前端同步。与特定 session 相关的数据,如果不直接呈现在前端,则应存储在仅后端变量中,以减少网络流量并提高性能。

他们的优势在于它们不需要是 JSON 可序列化的,但是它们仍然必须是 cloudpickle-able,以便在生产模式下与 redis 一起使用。它们不能直接在前端渲染,并且可能用于存储不应发送给客户端的敏感值。

例如,仅后端变量用于存储一个大数据结构,然后使用缓存变量将其分页到前端。

image-20250218163917828

import numpy as np


class BackendVarState(rx.State):
_backend: np.ndarray = np.array(
[random.randint(0, 100) for _ in range(100)]
)
offset: int = 0
limit: int = 10

@rx.var(cache=True)
def page(self) -> list[int]:
return [
int(x) # explicit cast to int
for x in self._backend[
self.offset : self.offset + self.limit
]
]

@rx.var(cache=True)
def page_number(self) -> int:
return (
(self.offset // self.limit)
+ 1
+ (1 if self.offset % self.limit else 0)
)

@rx.var(cache=True)
def total_pages(self) -> int:
return len(self._backend) // self.limit + (
1 if len(self._backend) % self.limit else 0
)

@rx.event
def prev_page(self):
self.offset = max(self.offset - self.limit, 0)

@rx.event
def next_page(self):
if self.offset + self.limit < len(self._backend):
self.offset += self.limit

@rx.event
def generate_more(self):
self._backend = np.append(
self._backend,
[
random.randint(0, 100)
for _ in range(random.randint(0, 100))
],
)

@rx.event
def set_limit(self, value: str):
self.limit = int(value)


def backend_var_example():
return rx.vstack(
rx.hstack(
rx.button(
"Prev",
on_click=BackendVarState.prev_page,
),
rx.text(
f"Page {BackendVarState.page_number} / {BackendVarState.total_pages}"
),
rx.button(
"Next",
on_click=BackendVarState.next_page,
),
rx.text("Page Size"),
rx.input(
width="5em",
value=BackendVarState.limit,
on_change=BackendVarState.set_limit,
),
rx.button(
"Generate More",
on_click=BackendVarState.generate_more,
),
),
rx.list(
rx.foreach(
BackendVarState.page,
lambda x, ix: rx.text(
f"_backend[{ix + BackendVarState.offset}] = {x}"
),
),
),
)

Using rx.field / rx.Field to improve type hinting for vars

When defining state variables you can use rx.Field[T] to annotate the variable's type. Then, you can initialize the variable using rx.field(default_value), where default_value is an instance of type T.

这种方法使变量的类型明确,有助于静态分析工具进行类型检查。此外,它会显示您的前端代码中允许修改变量的方法,因为它们在类型提示中列出。

import reflex as rx

app = rx.App()


class State(rx.State):
x: rx.Field[bool] = rx.field(False)

def flip(self):
self.x = not self.x


@app.add_page
def index():
return rx.vstack(
rx.button("Click me", on_click=State.flip),
rx.text(State.x),
rx.text(~State.x),
)

Computed Vars

Computed vars have values derived from other properties on the backend. They are defined as methods in your State class with the @rx.var decorator. A computed var is recomputed every time an event is processed in your app.

class UppercaseState(rx.State):
text: str = "hello"

@rx.var
def upper_text(self) -> str:
# This will be recomputed whenever `text` changes.
return self.text.upper()


def uppercase_example():
return rx.vstack(
rx.heading(UppercaseState.upper_text),
rx.input(
on_blur=UppercaseState.set_text,
placeholder="Type here...",
),
)

We recommend always using type annotations for computed vars.

Cached Vars 缓存变量

装饰为 @rx.var(cache=True) 的缓存变量是一种特殊类型的计算变量,仅在其依赖的其他状态变量更改时重新计算。这对于昂贵的计算很有用,但在某些情况下,它可能不会在您期望的时候更新。 Reflex 的早期版本具有 @rx.cached_var 装饰器,现在已被 @rx.var 的新 cache 参数取代。

class CachedVarState(rx.State):
counter_a: int = 0
counter_b: int = 0

@rx.var
def last_touch_time(self) -> str:
# This is updated anytime the state is updated.
return time.strftime("%H:%M:%S")

@rx.event
def increment_a(self):
self.counter_a += 1

@rx.var(cache=True)
def last_counter_a_update(self) -> str:
# This is updated only when `counter_a` changes.
return f"{self.counter_a} at {time.strftime('%H:%M:%S')}"

@rx.event
def increment_b(self):
self.counter_b += 1

@rx.var(cache=True)
def last_counter_b_update(self) -> str:
# This is updated only when `counter_b` changes.
return f"{self.counter_b} at {time.strftime('%H:%M:%S')}"


def cached_var_example():
return rx.vstack(
rx.text(
f"State touched at: {CachedVarState.last_touch_time}"
),
rx.text(
f"Counter A: {CachedVarState.last_counter_a_update}"
),
rx.text(
f"Counter B: {CachedVarState.last_counter_b_update}"
),
rx.hstack(
rx.button(
"Increment A",
on_click=CachedVarState.increment_a,
),
rx.button(
"Increment B",
on_click=CachedVarState.increment_b,
),
),
)

在这个例子中 last_touch_time 是一个普通的计算变量,它会在状态被修改时更新。 last_counter_a_update 是一个仅依赖于 counter_a 的计算变量,因此只有在 counter_a 发生变化时才会重新计算。类似地, last_counter_b_update 仅依赖于 counter_b ,因此只有在 counter_b 发生变化时才会更新。

Var Operations 变量操作

Var operations transform the placeholder representation of the value on the frontend and provide a way to perform basic operations on the Var without having to define a computed var.

在您的前端组件中,您不能在状态变量上使用任意的 Python 函数;This is because we compile the frontend to Javascript. 这是就要用到一些变量操作了

Supported Operations

  • Negate, Absolute and Length
    • - 运算符用于获取变量的负值。 abs() 运算符用于获取变量的绝对值。 .length() 运算符用于获取列表变量的长度。
  • 所有的比较运算符在 Python 中都如预期那样使用。包括 ==!=>>=<<=
  • 两个变量相加 + ,相减 - ,相乘 * 和将一个变量提升到幂 pow()
  • 运算符 / 表示真除法。运算符 // 表示地板除法。运算符 % 表示除法的余数
  • & 表示逻辑 AND。 | 表示逻辑 OR。
  • ~ 运算符用于反转一个变量。它用于类型为 bool 的变量,并等同于 not 运算符。
  • Var 类型不支持''in''运算符,必须使用 Var.contains() 。此时 var 必须是类型: dictlisttuplestr
  • 使用 reverse 操作来反转列表 var。var 必须是类型 list
  • 使用 join 操作将列表 var 连接成字符串
  • lower 运算符将字符串变量转换为小写。 upper 运算符将字符串变量转换为大写。 split 运算符将字符串变量拆分为列表。

Get Item (Indexing) 获取项目(索引)

索引仅支持字符串、列表、元组、字典和数据框。要索引到状态变量,需要严格的类型注释。

class GetItemState1(rx.State):
# list_1: list = [50, 10, 20] will not work
list_1: list[int] = [50, 10, 20]


def get_item_error_1():
return rx.vstack(
rx.progress(value=GetItemState1.list_1[0])
)

Custom Vars

如前所述,Reflex vars 必须是 JSON 可序列化的。

这意味着我们可以支持任何 Python 原始类型,以及列表、字典和元组。但是,您还可以通过继承 rx.Base 或使用 @dataclasses.dataclass 将它们装饰为数据类来创建更复杂的 var 类型。

import googletrans


class Translation(rx.Base):
original_text: str
translated_text: str


class TranslationState(rx.State):
input_text: str = "Hola Mundo"
current_translation: Translation = Translation(
original_text="", translated_text=""
)

@rx.event
def translate(self):
self.current_translation.original_text = (
self.input_text
)
self.current_translation.translated_text = (
googletrans.Translator()
.translate(self.input_text, dest="en")
.text
)


def translation_example():
return rx.vstack(
rx.input(
on_blur=TranslationState.setvar("input_text"),
default_value=TranslationState.input_text,
placeholder="Text to translate...",
),
rx.button(
"Translate", on_click=TranslationState.translate
),
rx.text(
TranslationState.current_translation.translated_text
),
)