useEffect() 永远不会被称为 preact

问题描述 投票:0回答:1

我正在使用 astro 和 preact。我希望这张卡每秒渲染并更新其计数器。它应该显示您有多久没有吸烟了。我在本地存储中存储了一个开始日期。当我尝试通过 js 脚本执行此操作时,它似乎有效。但是当我想使用 useEffect() 钩子时,计时器就会卡在 0 处。

index.astro

---
import 'bootstrap-icons/font/bootstrap-icons.css';
import BaseLayout from '../layouts/BaseLayout.astro';
import FunFact from '../components/FunFact.astro';
import Card from '../components/Card';
import SmokeFreeTimeCard from '../components/SmokeFreeTimeCard';
const pageTitle = "Übersicht";
---
<BaseLayout pageTitle={pageTitle}>

    <Card cardTitle="Funfact" iconClass="fa-regular fa-face-laugh">
        <FunFact />
    </Card>

    <SmokeFreeTimeCard cardTitle="Rauchfreie Zeit" iconClass="fa-solid fa-ban-smoking">
            
    </SmokeFreeTimeCard>

    <Card cardTitle="Finanzen" iconClass="fa-solid fa-money-bill">
        Du hast bereits <b>X€</b> gespart!<br/>
        Dein jähliches Ersparnis beläuft sich auf <b>XXXX€</b>. Das sind <b>XXX€</b> im Monat bzw. <b>XX€</b> am Tag!
    </Card>

    <Card cardTitle="Konsum" iconClass="fa-solid fa-wand-magic-sparkles">
        Du hast bereits <b>XX,XX Zigaretten</b> widerstanden.<br/>
        Auf ein Jahr gerechnet sind das <b>XX.XXX Stück</b>
    </Card>

    <script>
        import "../scripts/index.js";
    </script>
</BaseLayout>

卡.jsx

import 'bootstrap/dist/css/bootstrap.min.css';
import '@fortawesome/fontawesome-free/css/all.min.css';

const Card = ({ cardTitle, iconClass, children }) => (
  <div class="card" style={{ marginBottom: '20px' }}>
    <div class="card-header" style={{ color: '#ACEB98' }}>
      <i class={iconClass}></i> <b>{cardTitle}</b>
    </div>
    <div class="card-body">
      <p class="card-text">
        {children} {/* Hier werden die eingefügten Texte gerendert */}
      </p>
    </div>
  </div>
);

export default Card;

SmokeFreeTimeCard.jsx

import { useState, useEffect } from 'preact/hooks';
import Card from '../components/Card';

const SmokeFreeTimeCard = ({ cardTitle, iconClass }) => {
  const [timeElapsed, setTimeElapsed] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      const dateOfReturn = localStorage.getItem('dateOfReturn');
      console.log('Date of Return:', dateOfReturn); // Überprüfe das Datum im localStorage
      if (dateOfReturn) {
        const startDate = new Date(dateOfReturn);
        const currentDate = new Date();
        const elapsedMilliseconds = currentDate - startDate;
        console.log('Elapsed Milliseconds:', elapsedMilliseconds); // Überprüfe die vergangene Zeit
        setTimeElapsed(elapsedMilliseconds);
      }
    }, 1000);
  
    return () => clearInterval(interval);
  }, []);

  const formatTime = (milliseconds) => {
    const seconds = Math.floor(milliseconds / 1000);
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const remainingSeconds = seconds % 60;
    return `${hours} Stunden ${minutes} Minuten ${remainingSeconds} Sekunden`;
  };

  return (
    <Card cardTitle={cardTitle} iconClass={iconClass}>
        {typeof timeElapsed === 'number' && (
            <>Du bist <b>{formatTime(timeElapsed)}</b> rauchfrei! Weiter so!</>
          )}
    </Card>
  );
};

export default SmokeFreeTimeCard;
html reactjs local-storage preact astrojs
1个回答
0
投票

据我研究,我发现任何与浏览器相关的 API(文档和窗口)在 Astro 中都无法访问。由于

localStorage
也是`window的一部分,因此astro无法直接访问它。

由于 Astro 组件运行在服务器上,因此我们无法访问这些浏览器特定的对象。

解决方案:

解决此问题的解决方案是对 React/Preact 组件(无论在何处使用)进行“水合”。因此,我们需要一个

客户端指令来说明何时加载它。 为此,您只需将 client:load

添加到 index.astro 中的组件即可:

        <SmokeFreeTimeCard
            cardTitle="Rauchfreie Zeit"
            iconClass="fa-solid fa-ban-smoking"
            client:load
        />

另一种解决方案可能是使用您提到的旧经典
script
。正如 Astro 文档中提到的:

如果代码位于 Astro 组件中,请将其移至 frontmatter 之外的标签。这告诉 Astro 在文档和窗口可用的客户端上运行此代码。

© www.soinside.com 2019 - 2024. All rights reserved.