Astro で React コンポーネントを使用して読み込みを改善する


昨日は超クールな portfolio in Astro を作りました.ただし、その記事で述べたように、既存の Web サイトを複製しました.

マイナス面は、ヘッダーと証言スライダーが JavaScript を使用していることです.
それを現在の状態の Astro ファイルにコピーしただけなので、そのまま機能します.

JavaScript を使用したヘッダー ファイルの例:

---
import site from "../data/site.json";
const {nav} = site;
---
<header id="header">
    <ul>
        {nav.map((item) => (
            <li>
                <a href={item.link} target={item.target} rel="noopener noreferrer">{item.name}</a>
            </li>
        ))}
    </ul>
</header>
<script type="text/javascript">
const header = document.getElementById("header");
window.onscroll = function() {
  if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) {
    header.classList.add("active");
  } else {
    header.classList.remove("active");
  }
};
</script>


この特定の例はうまく機能しますが、これを React コードに変換して、Astro の読み込みをより有効に活用したいと考えました.

Astro コンポーネントを React に変換する



最初に行うことは、.astro ファイルを .jsx ファイル (React) に変換することです.

続行する前に、React を含めるようにレンダラーを設定しているかどうかを確認してください.
Astro.config.mjs ファイルを開き、レンダラーに次の要素が含まれていることを確認します.

renderers: ['@astrojs/renderer-react'],


それでは、ヘッダコンポーネントから始めましょう.

基本的な反応コンポーネントは次のようになります.

import React, {useState, useEffect} from 'react';
import site from '../../data/site.json';
const {nav} = site;
import './header.scss'; // include global CSS

const Header = () => {
  return (
    <header id="header">
      <ul>
        {nav.map((item, i) => (
          <li key={i}>
            <a href={item.link} target={item.target} rel="noopener noreferrer">
              {item.name}
            </a>
          </li>
        ))}
      </ul>
    </header>
  );
};
export default Header;


ご覧のとおり、このファイル全体を独自のフォルダー (ヘッダー) に移動し、このフォルダーにヘッダー用の css ファイルを追加しました.

しかし、今では JavaScript 部分全体が欠けているので、React のやり方でそれを追加し直しましょう.

const Header = () => {
  const [colorChange, setColorchange] = useState(false);

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  function handleScroll() {
    if (window.pageYOffset > 50) {
      return setColorchange(true);
    }
    return setColorchange(false);
  }

  return (
    <header id="header" className={colorChange ? 'active' : ''}>
      <ul>
        {nav.map((item, i) => (
          <li key={i}>
            <a href={item.link} target={item.target} rel="noopener noreferrer">
              {item.name}
            </a>
          </li>
        ))}
      </ul>
    </header>
  );
};


ここでは useEffect フックを使用してスクロール イベントをリッスンしています.これが発生している間に、handleScroll 関数を呼び出します.
コンポーネントが閉じたら、リスナーも削除します.

handleScroll 関数はスクロール オフセットをチェックし、それが 50 より大きい場合は、colorChange を true に設定します.

これは、ヘッダー要素の className に追加されます.

変更する必要がある最後の部分は、コンポーネントの実際のロードです.
これは pages/index.astro ファイルで行います.

基本的なインポートは新しいファイル拡張子に変更され、それに部分的なハイドレーションを追加できます.

部分水和には、次のタイプを使用できます.
  • client:load : ページ読み込み時のハイドレート
  • client:idle : メインスレッドが空いたらすぐにハイドレートする
  • client:visible : このコンポーネントがビューポートに到達するとすぐにハイドレートします
  • client:media={query} : 特定のメディア クエリが満たされたときにハイドレートする

  • この特定のものに load を使用します.

    import Header from '../components/header/Header.jsx';
    
    <Header client:load />;
    


    証言スライダーの変換



    このアプローチを使用して、証言スライダーを変換することもできます.
    これを React コンポーネント全体にすることにしたので、証言ラッパーとその中の要素です.

    まずはスライダーを見てみましょう.

    import React, {useState, useEffect} from 'react';
    import TestimonialItem from './TestimonialItem.jsx';
    import site from '../../data/site.json';
    const title = `Don't take my word for it`;
    const {testimonials} = site;
    import './testimonials.scss'; // include global CSS
    
    const Testimonials = () => {
      const [activeSlide, setActiveSlide] = useState(0);
    
      useEffect(() => {
        const timeout = setTimeout(() => {
          const newIndex = activeSlide + 1 === testimonials.length ? 0 : activeSlide + 1;
          setActiveSlide(newIndex);
        }, 5000);
    
        return () => {
          clearTimeout(timeout);
        };
      }, [activeSlide]);
    
      return (
        <section id="testimonials">
          <h2>{title}</h2>
          <div className="testimonial-grid">
            {testimonials.map((testimonial, i) => (
              <TestimonialItem key={i} item={testimonial} active={activeSlide === i} />
            ))}
          </div>
        </section>
      );
    };
    export default Testimonials;
    


    ここで起こっていることをたくさん引用してください.最も重要な部分は、アクティブな要素を自動再生したいということです.

    このための状態を作成し、間隔ごとに更新することにしました.
    つまり、カウンターを追加し、最後のスライドにある場合はリセットします.

    次に、このアクティブ状態を、アクティブにする必要がある特定の要素に渡します.

    これが TestimonialItem でどのように表示されるかを見てみましょう.

    import React from 'react';
    import './testimonials.scss'; // include global CSS
    
    const TestimonialItem = ({item, active}) => {
      return (
        <div className={active ? 'testimonial-item active' : 'testimonial-item'}>
          <div className="testimonial-item--inner">
            <img width="64" height="64" src={item.image} alt={item.name} />
            <div className="testimonial-item--content">
              <strong>
                {item.name} <i>{item.title}</i>
              </strong>
              <br />
              <p>{item.quote}</p>
            </div>
          </div>
        </div>
      );
    };
    export default TestimonialItem;
    


    ご覧のとおり、これも React コンポーネントに変換されています.
    これにより、React バインディングを活用してアイテムとアクティブ状態をバインドできます.

    次に、React 条件付きレンダリングを使用して、アクティブなクラスを 1 つの特定のアイテムに追加するかどうかを指定します.

    この特定のコンポーネントはページの下部にあるため、client:visible オプションを使用しましょう.

    import Testimonials from '../components/testimonials/Testimonials.jsx';
    
    <Testimonials client:visible />;
    


    かなりクールですよね?
    この特定のコンポーネントは、ビューポートでヒットした場合にのみ動作を開始するため、ロードが容易になります.

    ここでライブ デモを表示できます: Chris Bongers portfolio .
    または GitHub でソース コードを表示します.

    読んでくれてありがとう、接続しましょう!



    私のブログを読んでいただきありがとうございます.メール ニュースレターを購読して、Facebook に接続してください.