Language/React.js

[React] 감정일기장 프로젝트 : 웹 스토리지 연결과 배포 (완성)

JJcoding 2024. 10. 29. 11:19

웹 스토리지(Web Storage)

웹 브라우저 내장 DB

  • 웹 브라우저에 기본적으로 내장되어 있는 데이터베이스
  • 별도의 프로그램 설치가 필요 없다. 라이브러리 설치도 필요 없다.
  • 그냥 자바스크립트 내장함수 만으로도 접근이 가능하다.
    • 값을 저장 : localStorage.setItem(key, value)
    • 값을 꺼냄 : localStorage.getItem(key)
  • SessionStorage
    • 브라우저 탭 별로 데이터를 보관한다.
    • 탭이 종료되기 전에는 데이터를 유지한다. (새로고침 가능)
    • 탭이 종료되거나 꺼지면 데이터를 삭제한다.
  • LocalStorage
    • 사이트 주소별로 데이터를 보관한다.
    • 사용자가 직접 삭제하기 전까지는 데이터를 보관한다.

예시

  // key값은 무조건 원시타입만 가능
  // 값 저장
  localStorage.setItem("test", "hello");
  localStorage.setItem("person", JSON.stringify({ name: "다람쥐" }));

  // 값 꺼내오기
  console.log(localStorage.getItem("test"));
  console.log(JSON.parse(localStorage.getItem("person")));
  JSON.parse(undefined); // JSON.parse는 undefined나 null이 들어가면 에러를 뱉는다.

  // 값 제거
  localStorage.removeItem("test");

 

프로젝트에 적용하기
App.jsx

import "./App.css";
...생략

function reducer(state, action) {
  let nextState;
  switch (action.type) {
    case "INIT":
      return action.data;
    case "CREATE": {
      nextState = [action.data, ...state];
      break;
    }
    case "UPDATE": {
      nextState = state.map((item) =>
        String(item.id) === String(action.data.id) ? action.data : item
      );
      break;
    }
    case "DELETE": {
      nextState = state.filter((item) => String(item.id) !== String(action.id));
      break;
    }
    default:
      return state;
  }

  localStorage.setItem("diary", JSON.stringify(nextState));
  return nextState;
}

...생략

function App() {
  const [isLoding, setIsLoding] = useState(true);
  const [data, dispatch] = useReducer(reducer, []);
  const idRef = useRef(0);

  useEffect(() => {
    const storedData = localStorage.getItem("diary");
    if (!storedData) {
      setIsLoding(false);
      return;
    }
    const parsedData = JSON.parse(storedData);
    if (!Array.isArray(parsedData)) {
      setIsLoding(false);
      return;
    }

    let maxId = 0;
    parsedData.forEach((item) => {
      if (Number(item.id) > maxId) {
        maxId = Number(item.id);
      }
    });

    idRef.current = maxId + 1;

    dispatch({
      type: "INIT",
      data: parsedData,
    });
    setIsLoding(false);
  }, []);

	... 생략

  if (isLoding) {
    return <div>데이터 로딩중입니다람쥐...</div>;
  }

  return (
		...생략
  );
}

export default App;

  • dispatch로 data에 값을 넣다보니 로딩중 일 때 다른 컴포넌트에서 data를 사용하면 [] 빈 배열이 인식되어 오류가 발생한다. 이를 막기 위해 isLoding state를 선언하여 보완해주었다.

배포 준비

  • 페이지 타이틀 설정하기
    • 웹 브라우저 탭에 표시되는 페이지의 제목
  • Favicon 설정하기
    • 웹 브라우저 탭에 표시되는 페이지타이틀 옆 작은 아이콘
  • 오픈 그래프 태그 설정하기
    • 웹 사이트의 링크를 공유할 때 썸네일, 제목 등의 정보를 노출하는 것
  • 프로젝트 빌드(Build)


index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>다람쥐 일기장</title>
    <meta property="og:title" content="다람쥐 일기장" />
    <meta property="og:description" content="나만의 작은 다람쥐 일기장" />
    <meta property="og:image" content="/thumbnail.png" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>
  • 리액트는 싱글 페이지이기 때문에 title 태그에 값을 설정하면 어떤 페이지에서도 같은 값이 나온다.


usePageTitle.jsx

import { useEffect } from "react";

const usePageTitle = (title) => {
  useEffect(() => {
    const $title = document.getElementsByTagName("title")[0];
    $title.innerText = title;
  }, [title]);
};

export default usePageTitle;
  • 만약 title을 바꾸고 싶다면 useEffect와 자바스크립트로 설정할 수 있다.
  • usePageTitle 이라는 사용자 정의 훅을 만들어서 각 페이지에 적용할 수 있다.

배포

  • 프로젝트 빌드하기 : 터미널에서 npm run build 입력한다.
  • vercel에 들어가 회원가입 후 터미널에서 npm install -g vercel로 설치한다.
  • vercel login 명령어를 통해 로그인을 한다.
> Success! GitHub authentication complete for 내 매일
Congratulations! You are now logged in. In order to deploy something, run `vercel`.
💡  Connect your Git Repositories to deploy every branch push automatically (<https://vercel.link/git>).
  • 로그인이 성공된 후 터미널에 vercel을 입력하면 배포가 진행된다.
🔗  Linked to leejinjus-projects/emotion-diary (created .vercel and added it to .gitignore)
🔍  Inspect: <https://vercel.com/leejinjus-projects/emotion-diary/7FmFzNBozswBKb84a8HYCQrfFL1K> [2s]
✅  Production: <https://emotion-diary-2mcawvlvs-leejinjus-projects.vercel.app> [2s]
  • Production에 적힌 주소로 들어가면 내가 만든 프로젝트 배포가 완료된 것을 볼 수 있다.
  • 기능을 수정, 추가하고 난 뒤에도 똑같이 vercel 명령어를 입력하면 배포가 진행된다.


내가 만든 감정 일기장 완성!

https://emotion-diary-l05gdhbax-leejinjus-projects.vercel.app

 

다람쥐 일기장

나만의 작은 다람쥐 일기장

emotion-diary-l05gdhbax-leejinjus-projects.vercel.app

 

출처 : 한입 크기로 잘라먹는 리액트