如何在 Astro 中的组件之间共享状态?

2024-06-05

我相信我在代码中采用了错误的方法,如何在按钮单击中设置客户端首选项,该按钮单击用作全局 astro 组件中的道具?或者我应该怎么做?我知道这是可能的,因为 astro js 本身在他们的文档网站中这样做了! (下面是我的尝试的解释)

我目前正在开发一个 Astro Js 项目,这是我的个人作品集,我希望它向访问者展示一个选择首选语言的选项,所以最初我在所有 astro 组件中传递一个语言属性。因此,我尝试在索引或布局文件中创建一个按钮,我的所有组件都会在其中接收其道具,以更改此值,但我很快意识到这不是应该如何完成的:

index.astro:(错误)

---
let lang = "pt-br";
---
<div id="langBtn">
  <span id="brbtn">BR</span><span>|</span><span id="enbtn">EN</span>
</div>
<Layout title="Daniel Folio" lang={lang}>
  <Hero lang={lang} />
</Layout>

<script>
  function handleClick() {
    if(lang === "pt-br") {
       lang = "en";
    } else {
       lang = "pt-br";
    }
  }
  document
    ?.getElementById("langBtn")
    ?.addEventListener("click", handleClick);
</ script>

我意识到我们无法在客户端访问或更改服务器端变量。 因此,我尝试使用 Astro cookie 来检查语言 cookie 是否存在,否则创建一个,然后单击按钮时更改其值,但这也是不可能的,因为 Astro.cookies 在客户端不可用。


介绍

简介将重点关注以下问题的一般答案如何在 Astro 中的组件之间共享状态?解决方案部分将重点关注如何在 Astro 中使用 cookie 同步客户端和服务器组件.

在客户端组件之间共享状态和事件

  • 框架:Vue、Solid、Preact 等前端框架处理组件状态共享
  • 库:对于无需承诺给定框架即可使用的解决方案,请参阅https://github.com/nanostores/nanostores https://github.com/nanostores/nanostores有关 Astro Docs 的更多详细信息https://docs.astro.build/en/core-concepts/sharing-state/ https://docs.astro.build/en/core-concepts/sharing-state/
  • vanilla js(仅说明):与模块全局变量一样简单(正如用户 SP33D 提醒的那样)。注意导出变量是可能的,但导出函数是更理想的模式
const devices = {
  poster:{}
}}
function get_devices(){
  return devices
}
export{
  get_devices
}

完整的项目示例https://github.com/MicroWebStacks/astro-home-control/blob/2107f94d0ba9ca76b43777d8ca24eae99b3e78cc/src/libs/power_state.js#L7 https://github.com/MicroWebStacks/astro-home-control/blob/2107f94d0ba9ca76b43777d8ca24eae99b3e78cc/src/libs/power_state.js#L7

使用 vanilla js 共享状态和事件

  • Vanilla js :还可以在客户端组件之间使用自定义事件,其中 html 元素是事件的目标,如本例所示
...
event(panel,"update",data[name])
...
element.addEventListener("update",(event)=>{
      panel_set_state(name,event.detail)
    })

完整项目示例:https://github.com/MicroWebStacks/astro-home-control/blob/2107f94d0ba9ca76b43777d8ca24eae99b3e78cc/src/pages/index.astro#L54 https://github.com/MicroWebStacks/astro-home-control/blob/2107f94d0ba9ca76b43777d8ca24eae99b3e78cc/src/pages/index.astro#L54

客户端和服务器之间共享状态

服务器通过页面重新加载到客户端

  • 通过直接在 html 标签或 html 属性中嵌入变量<p class="value">{init}</p>(最简单也是最常见的)

  • 通过使用<script define:vars={{init}}>这可能是解决方案的一部分,但它不处理客户端->服务器反向链接,并且有缺点

    • the passed variable will get hardcoded in the script which becomes specific to the component instance (if you have 10 components, you get 10 scripts each in the body with the corresponding component instance value !!!) This is how it is translated enter image description here

    • 因此,脚本是内联的,不再捆绑、延迟加载(不再在头部资产中)

    • 没有缓存,在每个页面中获取,...

服务器到客户端无需重新加载页面

对于动态服务器更改变量,可以使用服务器发送事件https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

我不会在这里详细介绍它,因为这个问题不需要它,但它可以与 Astro 一起使用,并且可以在此处找到一个示例https://github.com/MicroWebStacks/astro-examples#03_sse-counter https://github.com/MicroWebStacks/astro-examples#03_sse-counter

在相同的范围内,也可以使用 websockets,但是对于这个问题来说,如果复杂性不是问题,那么也可以从客户端和服务器访问数据库。

服务器和客户端的持久性和同步

使用客户端存储

这是客户坚持其存储选择的一种可能的解决方案,缺点是

  • 如果存储只有客户端知道,服务器应答会闪烁
  • 或需要开发更多代码来处理客户端提交和服务器端端点捕获,这需要处理会话和用户管理!

对于那些对无闪烁状态高级示例感兴趣的人,请与 sessionStorage 和 url 参数共享这里的工作示例https://github.com/MicroWebStacks/astro-examples#14_client-storage-counter https://github.com/MicroWebStacks/astro-examples#14_client-storage-counter

使用cookie

这是最简单的方法,看解决方案

解决方案:如何使用cookie在Astro中同步客户端和服务器

问题帖子得到了正确的调查,然后陷入了如何使用 cookie 客户端:

这就是在客户端上设置和获取 cookie 所需的全部内容,只需几行普通的 JavaScript,没有依赖项。请参阅此问题/答案使用 JavaScript 设置 cookie 并获取 cookie https://stackoverflow.com/questions/14573223/set-cookie-and-get-cookie-with-javascript

这里针对计数器进行了缩小和定制,但对于过期处理,请参阅引用的问题

    function get_counter(){
        const entry = document.cookie.split(';').find(entry=>entry.replace(' ','').startsWith('counter='))
        if(entry){
            return parseInt(entry.split('=')[1])
        }else{
            return 0
        }
    }
    function set_counter(counter){
        document.cookie = `counter=${counter}`
        console.log(`new counter value = ${counter}`)
    }

客户端持久计数器示例

为了使示例更简单,我使用了计数器而不是语言 这是一个完整的例子

  • github项目:https://github.com/MicroWebStacks/astro-examples#13_client-persistent-counter https://github.com/MicroWebStacks/astro-examples#13_client-persistent-counter
  • 功能性的 Gitpod :https://gitpod.io/?on=gitpod#https://github.com/MicroWebStacks/astro-examples/tree/main/13_client-persistent-counter https://gitpod.io/?on=gitpod#https://github.com/MicroWebStacks/astro-examples/tree/main/13_client-persistent-counter

服务器端cookie的使用

在Astro中,计数器cookie可以如下使用

let counter = 0
const cookie = Astro.cookies.get("counter")
if(cookie?.value){
    counter = cookie.value
}
console.log(`index.astro> cookie counter = ${counter}`)

潜在问题

  • 确保 cookie 在部署主机中传递非常重要,因为这可能是阻止此解决方案的问题,可以在示例中使用服务器控制台日志进行检查
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Astro 中的组件之间共享状态? 的相关文章

随机推荐

  • apache ProxyPass:如何保留原始IP地址

    我们使用 ProxyPass 将所有 r 请求重定向到端口 18080 上的 jboss 如下所示 ProxyPreserveHost on ProxyPass r http localhost 18080 redirectService
  • 枚举

    我试图拥有一组扩展通用接口的枚举 例如 interface Fooable void someCommonMethod enum E1 implements Fooable some enumuerations and a definiti
  • 避免加密和编码的 URL 字符串中的换行符

    我正在尝试实现一个简单的字符串编码器来混淆 URL 字符串的某些部分 以防止它们被用户弄乱 我使用的代码几乎与示例中的相同JCA指南 http docs oracle com javase 6 docs technotes guides s
  • 可疑地使用“else”与 i/o 结合,看到“;”靠近“如果”

    以下是导致此问题的代码 if fromProc 0 MSG SLEEP nempty proc2clk 0 gt proc2clk 0 fromProc 0 Woke up fromProc 0 MSG SLEEP fromProc 0 M
  • 限制 FormFile 中的文件大小

    我让用户使用 FormFile 上传文件 我应该在什么时候检查文件大小是否太大 当我做 file header fileErr r FormFile file 文件对象已经创建 那么我是否已经产生了读取整个文件的成本 https golan
  • php平台安装询问我intl扩展,但似乎已经安装

    在 orocrm 安装期间 使用 symfony 2 开发的平台 我收到此错误 Fatal error Uncaught exception Symfony Component Intl Exception MethodArgumentVa
  • 如何将事件处理程序添加到 VB.NET 中的局部变量

    我在 VB NET 中有一个窗体 用作主窗体中的对话框 它的实例始终是本地定义的 没有对应的字段 当用户单击对话框中的 确定 按钮时 它将触发一个只有一个参数的事件 即我的类之一的实例 由于它始终是局部变量 因此如何为该事件添加事件处理程序
  • 如何从 jQuery 获取 ajax 请求下载 Excel

    我有一个 Spring MVC 视图 它提供了一个 excel 文件 但是 我现在修改了该过程 以便用户获得一个模式框 他们可以在下载 excel 之前在其中选择一些选项 这些选定的选项将发送到视图 我的请求看起来像这样 get downl
  • 如何在 Windows 上使用 Java Hotspot JVM 禁用小型转储 (mdmp) 文件生成

    目前 我有一个已部署的可执行 jar 文件 该文件在崩溃时会创建大型 7 Gb 小型转储文件 我想要一个导致崩溃原因的文本表示 而不是 JVM 状态的二进制文件 我尝试使用中找到的信息这个 CodeRanch 帖子 http www cod
  • 我们应该使用 Eval 还是 Databind 事件?

    当使用 Asp Net 并使用 ListView 等控件创建网站时 使用 Eval 命令是一个好习惯吗 还是应该在 databind 事件中填充文字和数据 取决于您是否想在更新事件上写回数据 在这种情况下数据绑定 如果您只想读取该数据 可以
  • 使用 Microsoft Graph 创建用户

    如何使用 Microsoft graph 创建用户 因为我在保存过程中遇到了权限失败的问题 我确实有几个问题 在图中调用创建用户 API 将在哪里创建用户 是在 Azure AD 还是其他地方 我尝试通过传递 json 和必需的标头来调用创
  • 使用 .htaccess 阻止直接访问 Pdf 文件

    这个问题已经出现过好几次了 我已经尝试了所有可用的选项 但我仍然很难阻止使用绝对 URL 直接访问 pdf 文件 我在 htaccess 文件中使用以下代码 该文件位于 pdf 所在的同一文件夹中 Order Allow Deny
  • Angular + Material - 如何使用 formgroup 处理多个复选框

    我有一个从后端获得的兴趣列表 我希望用户能够选择他们想要的兴趣 我将只存储他们在数据库中检查的兴趣 并在他们加载页面时预先填充 但首先我需要获取用户选择的这些兴趣 兴趣组件 ts export class InterestsComponen
  • T-SQL - 是否有(免费)方法来比较两个表中的数据?

    I have table a and table b SQL Server 2008 两个表具有完全相同的架构 出于本问题的目的 请考虑table a 我的本地开发表 table b 实时表 我需要创建一个 SQL 脚本 包含UPDATE
  • 如何在 Android 中不使用 Intent 裁剪图像

    我正在尝试裁剪图像我使用了下面的代码 意图 i new Intent Intent ACTION PICK android provider MediaStore Images Media EXTERNAL CONTENT URI i pu
  • C++ 析构函数:何时释放内存?

    如果我删除一个导致其析构函数被调用的对象 那么内存是在析构函数完成函数中的任何操作之前还是之后被释放 仅当最小派生类子对象被销毁后才会释放内存 所以如果你有 class Base class Derived public Base publ
  • 在 C++ 中处理音频缓冲区时,如何执行从 float -> double -> float 的转换

    我目前正在开发一个应用程序 其中音频样本帧在以下回调中进行处理 void Eav07AudioProcessor processBlock AudioSampleBuffer buffer for int channel 0 channel
  • NodeJS 中的缩进多行日志记录

    我要打印JSON stringify d 反对控制台 将上下文作为 Mocha 测试套件输出的一部分 当测试缩进时 我希望对象日志行向右缩进足够远 例如 3 4 个制表符空格 以便它们可以识别地位于右侧describe group 我怎样才
  • 在字符串内打印单引号

    我想输出 XYZ s ABC 我在Python IDLE中尝试了以下3条语句 第一条和第二条语句输出 a before 带打印功能的第三条语句不输出 before 作为 Python 新手 我想了解为什么 之前输出 在第 1 条和第 2 条
  • 如何在 Astro 中的组件之间共享状态?

    我相信我在代码中采用了错误的方法 如何在按钮单击中设置客户端首选项 该按钮单击用作全局 astro 组件中的道具 或者我应该怎么做 我知道这是可能的 因为 astro js 本身在他们的文档网站中这样做了 下面是我的尝试的解释 我目前正在开