实践reflex:项目架构解析

ops/2024/12/23 0:24:47/

 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 rxfrom ..state import AuthStateclass 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 Callableimport reflex as rxfrom .components.menu import menu
    from .components.navbar import navbardef 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 rxclass SettingsState(rx.State):refresh_interval: int = 15auto_update: bool = Trueprefer_plain_text: bool = Trueposts_per_page: int = 20def settings_dialog():return rx.dialog(...)

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

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

import reflex as rxfrom ..models import Post
from ..template import template
from ..components.settings import SettingsStateclass PostsState(rx.State):refresh_tick: intpage: intposts: 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 = 0async 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 - 1def 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_cacheimport reflex as rxclass 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.ppmy.cn/ops/107422.html

相关文章

u盘显示需要格式化才能用预警下的数据拯救恢复指南

U盘困境&#xff1a;需要格式化的紧急应对 在数字信息爆炸的时代&#xff0c;U盘作为便携的数据存储介质&#xff0c;承载着我们工作、学习乃至生活中的大量重要资料。然而&#xff0c;当U盘突然弹出“需要格式化才能用”的提示时&#xff0c;这份便捷瞬间转化为焦虑与不安。这…

Dify.ai:部署自己的 AI 应用、知识库机器人,简单易用

Dify.ai:部署自己的 AI 应用、知识库机器人,简单易用 今天,来分享下 Dify.AI 这个产品,一句话介绍:可供普通人简单易用的部署生成出一个 AI 应用。这是一种使用人工智能技术来帮助团队开发和运营 AI 应用的工具。 什么是 Dify.ai Dify.ai 是一个易于使用的 LLMOps 平台…

驾驭冰雪 安全无忧,韩泰高性能冬季轮胎新品上市

- 韩泰轮胎推出冬季轮胎新产品Winter i*cept iZ3和SUV专用的Winter i*cept iZ3 X - 新轮胎采用了V型花纹&#xff0c;冰雪路面安全性极佳&#xff0c;而且具有操控性好、续航里程长的优点 - 新轮胎在位于北极圈以北300km的韩泰轮胎芬兰伊瓦洛测试场进行了严苛测试&#xff0c…

鸿蒙开发5.0【Picker的受限权限适配方案】

Picker由系统独立进程实现&#xff0c;应用可以通过拉起Picker组件&#xff0c;用户在Picker上选择对应的资源&#xff08;如图片、文档等&#xff09;&#xff0c;应用可以获取Picker返回的结果。 类型受限权限使用的picker音频ohos.permission.READ_AUDIO&#xff0c;ohos.p…

某里227逆向分析

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关。 本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除! 前言 这次会简单的讲解…

深入理解 Go 中的 defer、panic 、日志管理与WebAssembly

延迟执行 (defer) 关键字的使用 在 Go 语言中&#xff0c;defer 关键字用于推迟某个函数的执行&#xff0c;直到其所在的外层函数即将返回时才执行。这在文件输入输出操作中非常有用&#xff0c;因为它允许你在打开文件后直接将关闭文件的操作放在附近&#xff0c;从而避免忘记…

springboot数据库连接由localhost改成IP以后访问报错500(2024/9/7

步骤很详细&#xff0c;直接上教程 情景复现 一.没改为IP之前正常 二.改完之后报错 问题分析 SQL没开启远程连接权限 解决方法 命令行登入数据库 mysql -u root -p切换到对应数据库 use mysql;设置root用户的连接权限允许其他IP连接数据库 update user set host % whe…

从源码角度分析 Kotlin by lazy 的实现

by lazy 的作用 延迟属性(lazy properties) 是 Kotlin 标准库中的标准委托之一&#xff0c;可以通过 by lazy 来实现。 其中&#xff0c;lazy() 是一个函数&#xff0c;可以接受一个 Lambda 表达式作为参数&#xff0c;第一次调用时会执行 Lambda 表达式&#xff0c;以后调用…