[React Library] react-helmet-async

Chanki Hong·2023년 7월 29일
1

React

목록 보기
17/17
post-thumbnail

SEO를 고려할 때,

CSR 프로젝트에서는 단순히 헬멧(react-helmet-async)을 사용하는 것만으로는 SEO 문제를 완벽하게 해결할 수 없습니다. 주의해야 할 점은 대부분의 검색 엔진과 크롤러는 JavaScript를 작동하지 않고, 단순한 서버 응답을 기반으로 페이지를 색인합니다. 따라서 CSR의 경우 동적인 메타데이터가 아닌 index.html의 메타 데이터를 그대로 이용합니다. (헬멧으로 적용한 동적 메타데이터를 제외한 index.html의 메타 데이터만 조회 됨) 이러한 이유로 SEO 문제를 완전히 해결하려면 SSR을 이용하는 것이 더 적합합니다.

react-helmet-async

  • react-helmet 의 메모리 누수와 데이터 무결성 저하 등의 버그 개선 버전.
  • 페이지 각각의 메타데이터(태그) 설정이 어려웠던,
  • SPA의 단점을 보완 가능.
  • 각 페이지의 <head> 태그를 설정 할 수 있음.

1. 설치

npm i react-helmet-async

2. 설정

  • index.tsx(js) 파일에 import { HelmetProvider } from 'react-helmet-async'; 를 추가하고,
  • <App /> 컴포넌트를 <HelmetProvider> 로 래핑.
  • <Helmet> 컴포넌트는 항상 <HelmetProvider> 컴포넌트 안에 존재해야 하기 때문.
  • <Helmet> 컴포넌트는 해당 페이지의 <head> 태그로 생각하면 됨.

CSR

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <HelmetProvider>
        <App />
      </HelmetProvider>
    </BrowserRouter>
  </React.StrictMode>
);

serviceWorkerRegistration.register();
reportWebVitals();

SSR

  • helmetContext 변수를 <HelmetProvider>context 로 전달 해야함.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';

const helmetContext = {};

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <HelmetProvider context={helmetContext}>
        <App />
      </HelmetProvider>
    </BrowserRouter>
  </React.StrictMode>
);

serviceWorkerRegistration.register();
reportWebVitals();

3. 사용

  • 메타데이터가 동적으로 바뀔 페이지(컴포넌트)에서 import { Helmet } from 'react-helmet-async'; 추가 뒤,
  • <Helmet> 태그를 이용해 <head> 를 작성.
  • react-helmet-async는 뎁스(depth)가 큰(깊숙한 곳에 위치한) <Helmet>이 우선권을 가짐.(오버라이드; Override)

디폴트 메타태그

  • 디폴트 메타태그는 App.tsx(js)<Helmet> 태그로 정의.
  • 주의할 점은 index.html 에 존재하는 메타데이터와 중복이 없어야 함.
  • 동적으로 바뀔 메타데이터는 App.tsx(js) 에서 디폴트 메타태그로 지정하고,
  • 동적으로 바뀔 필요가 없는 데이터(robots, API 권한 등)는 index.html 에서 지정하는 방법이 좋아보임.
// App.tsx

import React, { useState, useEffect } from 'react';
import { Reset } from 'styled-reset';
import './style/App.scss';
import { Routes, Route } from 'react-router-dom';
import { Helmet } from 'react-helmet-async';
import Header from './component/Header';
import Bus from './page/Bus';
import Footer from './component/Footer';
import MenuBox from './component/MenuBox';
import Home from './page/Home';
import SpinLogo from './component/SpinLogo';
import Meal from './page/Meal';

function App() {
  return (
    <>
      <Reset />
      <Helmet>
        <title>더존 빵돌이</title>
        <meta name='keywords' content='버스, 시간, 식당, 식단, 날씨, 회식장소, 빵돌이, 맛집, 카페, 생활정보' />
        <meta name='description' content='구내식당 식단과 통근 버스의 실시간 도착 시간을 안내하는 더존 빵돌이 웹 서비스입니다.' />
        {/* 오픈그래프(Open Graph) */}
        <meta property='og:url' content='https://breadkun.com/' />
        <meta property='og:title' content='더존 빵돌이' />
        <meta property='og:type' content='website' />
        <meta property='og:image' content='./logo/og-image.png' />
        <meta property='og:description' content='구내식당 식단과 통근 버스의 실시간 도착 시간을 안내하는 더존 빵돌이 웹 서비스입니다.' />
      </Helmet>
      <Header setMenuBox={setMenuBox} />
      <Routes>
        <Route path='/' element={<Home setMenuBox={setMenuBox} />} />
        <Route path='/meal' element={<Meal setMenuBox={setMenuBox} />} />
        <Route path='/cafe' element={<SpinLogo text1={'COMMING SOON'} text2={'서비스 준비중입니다.'} minHeight='80vh' />} />
        <Route path='/omakase' element={<SpinLogo text1={'COMMING SOON'} text2={'서비스 준비중입니다.'} minHeight='80vh' />} />
        <Route path='/bus' element={<Bus setMenuBox={setMenuBox} />} />
        <Route path='/bus/:destination' element={<Bus setMenuBox={setMenuBox} />} />
        <Route path='*' element={<SpinLogo text1={'404 Not Found'} text2={'페이지를 찾을 수 없습니다.'} minHeight='80vh' />} />
      </Routes>
      <Footer />
    </>
  );
}

export default App;

페이지 별 메타태그

// Meal.tsx

import React from 'react';
import { Helmet } from 'react-helmet-async';

function Meal({ setMenuBox }: { setMenuBox: React.Dispatch<React.SetStateAction<boolean>> }) {
  return (
    <>
      <Helmet>
        <title>더존 빵돌이 | 식단</title>
        <meta name='keywords' content='식당, 식단, 날씨, 회식장소, 맛집, 카페' />
        <meta name='description' content='더존ICT의 구내식당 식단입니다.' />
        {/* 오픈그래프(Open Graph) */}
        <meta property='og:url' content='https://breadkun.com/meal' />
        <meta property='og:type' content='website' />
        <meta property='og:image' content='./logo/og-image.png' />
        <meta property='og:title' content='더존 빵돌이 | 식단' />
        <meta property='og:description' content='더존ICT의 구내식당 식단입니다.' />
      </Helmet>
      <div className={ms('meal')}>
      </div>
    </>
  );
}

export default Meal;

반복 줄이기

  • 컴포넌트로 만들어 반복을 줄일 수 있음.
// BreadkunHelmet.tsx

import React from 'react';
import { Helmet } from 'react-helmet-async';

function BreadkunHelmet({ title, description, keywords, url, img }: { title: string; description: string; keywords: string; url: string; img: string }) {
  return (
    <Helmet>
      <title>{title}</title>
      <meta name='keywords' content={keywords} />
      <meta name='description' content={description} />
      {/* 오픈그래프(Open Graph) */}
      <meta property='og:type' content='website' />
      <meta property='og:url' content={url} />
      <meta property='og:image' content={img} />
      <meta property='og:title' content={title} />
      <meta property='og:description' content={description} />
    </Helmet>
  );
}

BreadkunHelmet.defaultProps = {
  title: '더존 빵돌이 | 다양한 더존ICT 생활 정보',
  description: '더존ICT의 구내식당 식단, 통근 버스의 실시간 도착 시간, 오늘의 빵, 사내 카페 메뉴, 날씨 등 다양한 생활 정보를 안내하는 더존 빵돌이 웹 서비스입니다.',
  keywords: '빵돌이, 더존ICT, 더존, 생활정보, 버스, 시간, 식당, 식단, 날씨, 회식장소, 맛집, 카페',
  url: 'https://breadkun.com/',
  img: './logo/og-image.png',
};
export default BreadkunHelmet;

1개의 댓글

comment-user-thumbnail
2023년 7월 29일

글 잘 봤습니다.

답글 달기