当前位置: 首页 > article >正文

实践reflex:项目架构解析

 reflex 是一个使用纯Python构建全栈web应用的库,但是需要使用node,所以你懂的。

reflex安装:实践reflex:一个使用纯Python构建全栈web应用的库-CSDN博客

创建hello项目

(base) sky@ub:~$ mkdir hello
(base) sky@ub:~$ cd hello/
(base) sky@ub:~/hello$ reflex init
─────────────────────── Initializing hello ────────────────────────
[06:42:32] Initializing the web directory.           console.py:104
Warning: Failed to fetch templates. Falling back to default 
template.
[06:42:50] Initializing the app directory.           console.py:104
Success: Initialized hello

项目路径结构:

hello
├── .web
├── assets
├── hello
│   ├── __init__.py
│   └── hello.py
└── rxconfig.py

 其中.web是隐藏目录,需要ls -la 才能看到。

.web 

这是编译的Javascript文件的存储位置。您永远不需要触摸此目录,但它对调试很有用。

每个Reflex页面都将编译为.web/pages目录中相应的.js文件。

assets资产

目录是您可以存储任何您想要公开可用的静态资产的地方。这包括图像、字体和其他文件。

例如,如果您将图像保存到assets/image.png,您可以从应用程序中显示它,如下所示:

rx.image(src="image.png")

主目录hello

每个项目的主目录,都跟项目名字一样。

初始化您的项目会创建一个与应用程序同名的目录。您将在这里编写应用程序的逻辑。

Reflex在hello/hello.py文件中生成一个默认应用程序。您可以修改此文件来自定义您的应用程序。

配置

rxconfig.py文件

应用程序模块

Reflex根据config中的app_name导入主应用程序模块,该模块必须将模块级全局命名app定义为rx.App的实例

主应用程序模块负责导入构成应用程序的所有其他模块,并定义app = rx.App()

包含页面、状态和模型的所有其他模块必须由主应用程序模块或软件包导入,以便Reflex将它们包含在编译的输出中。

更详细的说明

页面包:example_big_app/pages

所有复杂的应用程序都将有多个页面,因此建议创建example_big_app/pages作为软件包。

  1. 此软件包应在应用程序中每页包含一个模块。
  2. 如果特定页面取决于状态,则该子状态应在与页面相同的模块中定义。
  3. 返回页面的函数应该用rx.page()进行装饰,以便将其作为路由添加到应用程序中。
import reflex as rx

from ..state import AuthState


class LoginState(AuthState):
    def handle_submit(self, form_data):
        self.logged_in = authenticate(
            form_data["username"], form_data["password"]
        )


def login_field(name: str, **input_props):
    return rx.hstack(
        rx.text(name.capitalize()),
        rx.input(name=name, **input_props),
        width="100%",
        justify="between",
    )


@rx.page(route="/login")
def login():
    return rx.card(
        rx.form(
            rx.vstack(
                login_field("username"),
                login_field("password", type="password"),
                rx.button("Login"),
                width="100%",
                justify="center",
            ),
            on_submit=LoginState.handle_submit,
        ),
    )

模板:example_big_app/template.py

大多数应用程序在页面之间保持一致的布局和结构。在单独的模块中定义此通用结构有助于在构建单个页面时轻松共享和重复使用。

最佳实践

  1. 将常见的前端用户界面元素分解为返回组件的函数。
  2. 如果一个函数接受返回组件的函数,它可以用作装饰器,如下所示。
    from typing import Callable
    
    import reflex as rx
    
    from .components.menu import menu
    from .components.navbar import navbar
    
    
    def template(
        page: Callable[[], rx.Component]
    ) -> rx.Component:
        return rx.vstack(
            navbar(),
            rx.hstack(
                menu(),
                rx.container(page()),
            ),
            width="100%",
        )
    

状态管理

进入其它状态

在以前的版本中,如果应用程序想要将设置与用于修改的页面或组件一起存储在SettingsState中,则需要访问这些设置的任何其他具有事件处理程序的状态必须从SettingsState继承,即使其他状态大多是正交的。另一种状态现在也必须始终加载设置,即使对于不需要访问它们的事件处理程序也是如此。

更好的策略是仅从需要访问子状态的事件处理程序中按需加载所需状态。

设置组件

example_big_app/components/settings.py
import reflex as rx


class SettingsState(rx.State):
    refresh_interval: int = 15
    auto_update: bool = True
    prefer_plain_text: bool = True
    posts_per_page: int = 20


def settings_dialog():
    return rx.dialog(...)

帖子页面:example_big_app/pages/posts.py

此页面加载SettingsState,以确定每页显示多少个帖子以及刷新频率。

import reflex as rx

from ..models import Post
from ..template import template
from ..components.settings import SettingsState


class PostsState(rx.State):
    refresh_tick: int
    page: int
    posts: list[Post]

    async def on_load(self):
        settings = await self.get_state(SettingsState)
        if settings.auto_update:
            self.refresh_tick = (
                settings.refresh_interval * 1000
            )
        else:
            self.refresh_tick = 0

    async def tick(self, _):
        settings = await self.get_state(SettingsState)
        with rx.session() as session:
            q = (
                Post.select()
                .offset(self.page * settings.posts_per_page)
                .limit(settings.posts_per_page)
            )
            self.posts = q.all()

    def go_to_previous(self):
        if self.page > 0:
            self.page = self.page - 1

    def go_to_next(self):
        if self.posts:
            self.page = self.page + 1


@rx.page(route="/posts", on_load=PostsState.on_load)
@template
def posts():
    return rx.vstack(
        rx.foreach(PostsState.posts, post_view),
        rx.hstack(
            rx.button(
                "< Prev", on_click=PostsState.go_to_previous
            ),
            rx.button(
                "Next >", on_click=PostsState.go_to_next
            ),
            justify="between",
        ),
        rx.moment(
            interval=PostsState.refresh_tick,
            on_change=PostsState.tick,
            display="none",
        ),
        width="100%",
    )

共同状态:example_big_app/state.py

由多个页面或组件共享的通用状态和子状态应在单独的模块中实现,以避免循环导入。此模块不应在应用程序中导入其他模块。

组件的可重复使用性

在Reflex中重复使用组件的主要机制是定义一个返回组件的函数,然后在需要该功能的地方简单地调用它。

组件函数通常不应将任何状态类作为参数,而是倾向于导入所需的状态并直接访问类上的变量。

记忆功能以提高性能

在大型应用程序中,如果一个组件有许多子组件或在大量位置使用,它可以提高编译和运行时性能,使用@lru_cache装饰器对函数进行内啮。

要回忆foo组件以避免多次重新创建,只需将@lru_cache添加到函数定义中,该组件将仅每组唯一参数创建一次。

from functools import lru_cache

import reflex as rx


class State(rx.State):
    v: str = "foo"


@lru_cache
def foo():
    return rx.text(State.v)


def index():
    return rx.flex(
        rx.button(
            "Change",
            on_click=State.set_v(
                rx.cond(State.v != "bar", "bar", "foo")
            ),
        ),
        *[foo() for _ in range(100)],
        direction="row",
        wrap="wrap",
    )

示例_大_应用程序/组件

此软件包包含应用程序的可重复使用部分,例如页眉、页脚和菜单。如果特定组件需要状态,则子状态可以在同一区域模块中定义。组件模块中定义的任何子状态应仅包含与该单个组件相关的字段和事件处理程序。

外部组件

Reflex 0.4.3引入了对reflex componentCLI命令的支持,这使得它可以轻松捆绑通用功能,作为独立的Python软件包在PyPI上发布,可以在任何Reflex应用程序中安装和使用。

在包装npm组件或其他自包含的功能片段时,将此复杂性移出应用程序本身可能会有所帮助,以便于在其他应用程序中更易于维护和重复使用。

数据库模型:example_big_app/models.py

建议在单个文件中实现所有数据库模型,以便更容易定义关系和理解整个模式。

然而,如果模式非常大,则有一个models包,在自己的模块中定义了单个模型,这可能是有意义的。

无论如何,单独定义模型允许任何页面或组件导入和使用它们,而无需循环导入。

顶级套餐:example_big_app/__init__.py

这是一个导入所有状态、模型和页面的好地方,这些状态、模型和页面应该是应用程序的一部分。通常,组件和助手不需要导入,因为它们将由使用它们的页面导入(或者它们将未使用)。

from . import state, models
from .pages import (
    index,
    login,
    post,
    product,
    profile,
    schedule,
)

__all__ = [
    "state",
    "models",
    "index",
    "login",
    "post",
    "product",
    "profile",
    "schedule",
]


http://www.kler.cn/news/294759.html

相关文章:

  • 去中心化网络:Web3如何颠覆传统互联网
  • 标准IO与系统IO
  • Java架构师未来篇大模型
  • 新加坡服务器:亚洲地区的优选之选
  • 【软件工程】软件开发模型
  • k8s中的层级结构,及节点组件的作用
  • Termius for Mac/Win:高效、安全的跨平台多协议远程管理软件
  • 黑马点评2——商户查询缓存(P37店铺类型查询业务添加缓存练习题答案)redis缓存、更新、穿透、雪崩、击穿、工具封装
  • 2-85 基于matlab的FrFT下时变幅度LFM信号参数估计
  • ROADM(可重构光分插复用器)-介绍
  • LTE PSS主同步信号搜索 MATLAB实现
  • 开发台球助教小程序前景分析
  • 高效传输秘籍,揭秘Rsync和SCP的优劣,助你做出明智选择!
  • RedisStack十部曲之二:Redis的核心概念
  • (五)vForm 动态表单文件上传、下载
  • 代码随想录算法训练营Day37|完全背包问题、518.零钱兑换II、377. 组合总和 Ⅳ、70. 爬楼梯(进阶版)
  • 连续信号的matlab表示
  • nginx 新建一个 PC web 站点
  • 前端HTML基础笔记
  • Docker数据卷和Dockerfile
  • 集成电路学习:什么是PWM脉冲宽度调制
  • vue通过url下载文件并重命名
  • Window下编译OpenJDK17
  • 【重学 MySQL】十五、过滤数据
  • 【vue css】background设置背景图片不显示问题
  • 利用人类反馈优化文本摘要质量
  • 力扣刷题--1534. 统计好三元组【简单】
  • 如何用RoBERTa高效提取事件文本结构特征:多层次上下文建模与特征融合
  • 如何快速融入大学课堂
  • 快排Java