쇼핑몰 프로젝트(memo,PWA,LocalStorage)

코딩애플 님의 강의를 바탕으로한 글입니다:)

만약 다음과 같이 상위컴포넌트에서 데이터를 받아서 쓰고 있는 하위컴포넌트가 있다.

이때, child1 컴포넌트의 내용을 존박에서 존박2로 바꾼다.
그렇다면 데이터는 재렌더링 되어 출력될 것이다.

하지만 child1 child2 두개 모두 재렌더팅이 된다.
상위 컴포넌트를 구성하는 state 또는 props 값이 변경되면 그와 관련된 모든 컴포넌트가 다 재렌더링이 되기 때문이다.

memo()

불필요한 재렌더링을 막는 함수

  1. memo함수를 import 해오자.
import React, {useEffect, memo} from 'react';
  1. 재렌더링이 불필요한 함수를 memo()함수로 감싸준다.
let Child2 = memo(function(){
  useEffect( ()=>{ console.log('렌더링됨2') } );
  return <div>2222</div>
})

이때 함수 선언을 변수에 선언하는 식으로 바꿔주면 되겠다.

function 함수(){}
let 함수 = function(){ }

주의) 하지만, props가 매우 방대하고 클 경우 손해일 수 있다.
기존 props와 바뀐 props를 비교하는 연산이 진행되는데, props가 크고 복잡하면 이 과정 자체도 부담이 될 수 있기 때문이다.

PWA

Progressive Web Application : 새롭고 강력한 소프트웨어 앱을 만드는 방식

1. 스마트폰, 테블릿 바탕화면에 웹사이트를 설치 가능
2. 오프라인에서도 동작
3. 설치 유도 비용이 매우 적다.

HTML, CSS, JS 를 이용해 만든 웹앱을 모던한 웹 브라우저 APIs 와 결합해서 크로스 플랫폼에서 동작하는 어플리케이션을 손쉽게 만들 수 있다.

즉, 이미 만든 웹사이트 또는 웹어플리케이션이 있다면 손쉽게 몇가지만 추가하면 데스크탑과 모바일에서도 동작하는 어플리케이션을 만들 수 있다.

안드로이드나 아이폰처럼 특정한 플랫폼에서 동작하는 네이티브 어플리케이션을 플랫폼에서 제공하는 다양한API를 이용해서 사용자에게 다양한 기능을 제공하는 역량이 크지만 앱 스토어를 이용해서 설치 해야하고 그 플랫폼에서만 사용할 수 있다는 단점이 있다.

반대로 브라우저에서 동작하는 웹앱은 플랫폼에 상관없이 브라우저만 있으면 사용가능하므로 사람들이 쉽게 접근할 수 있다는 장점이 있지만, 네이티브앱처럼 플랫폼 자체의 API를 사용할 수 없다는 단점이 있다.

  1. 만약 기존에 만들던 프로젝트가 pwa 기반의 template이 아니었다면,일단 새로 프로젝트를 하나 만들어서 복사 붙여넣기 해주자. (라이브러리 설치도.)
 npx create-react-app 프로젝트명 --template cra-template-pwa
  1. index.js 에서 아래와 같이 register로 변경.
    그럼 yarn build / npm run build 했을 때 manifest.json과 service-worker.js 파일이 자동으로 생성. 하지만, 위에서 처음부터 pwa 형식의 프로젝트였음으로 두 파일이 존재할 것이다.(두개 파일은 PWA에서 필수파일)
serviceWorkerRegistration.unregister();
-> 
serviceWorkerRegistration.register();
  1. manifest.json 파일은 웹앱의 정보를 보여준다.(아이콘, 이름, 테마색)
{
  "version" : 버전.. 예를 들면 1.12",
  "short_name" : "설치후 앱런처나 바탕화면에 표시할 짧은 12자 이름",
  "name" : "기본이름",
  "icons"(src) : { 여러가지 사이즈별 아이콘 이미지 경로(운영체제에 따라) },
  "start_url" : "앱아이콘 눌렀을 시 보여줄 메인페이지 경로",
  "display" : "standalone(상단바 제거) 아니면 fullscreen",
  "background_color" : "앱 처음 실행시 잠깐 뜨는 splashscreen의 배경색",
  "theme_color" : "상단 탭색상 등 원하는 테마색상",
}
  1. service.-worker.js 파일은 프로젝트 내의 CSS,JS,HTML,이미지 파일 등이 하드에 설치할지 결정한다. 즉, 파일을 요청하는 것이 아니라 Cache Storage에 저장(캐싱)되어 있는 형식으로 오프라인에서도 앱이 사용이 가능한 것.

  2. 생성된 build 파일을 별도의 비쥬얼스튜디오코드에서 오픈하여 liver server을 키면 정상적으로 작동되는지 확인이 가능하다. (설치 버튼이 뜨는 것도 확인 가능)

LocalStorage

새로고침하면 JS파일들은 다시 읽히기 때문에 구현했던 기능들이 리셋된다.
따라서, 데이터를 서버에 저장해야 하는데, 이를 대신해서 브라우저에 정보를 저장하고 싶을 때 쓸 수 있는 저장 공간이 LocalStorage이다.

localSotorage 문법

  1. localStorage.setItem('데이터이름', '데이터');
  • 다음과 같이 key값과 value값에 저장.
  1. localStorage.getItem('데이터이름');
  • 다음과 같이 '데이터이름'에 대한 value값이 출력.
  1. localStorage.removeItem('데이터이름')
  • 데이터가 로컬스토리지에서 삭제.

만약 localStorage에 오브젝트 또는 배열을 저장하려면 바로 저장이 불가능하다.
localStorage에는 텍스트 자료만 저장이 가능하므로, JSON형식으로 변경 후 저장해야 한다.

JSON.stringfy()를 함수로 문자처럼 인식시킨다.
localStorage.setItem('obj', JSON.stringify({name:'kim'}) );

그리고 만약 저장된 데이터를 출력하고 싶은데, 그냥 출력하면 JSON형식으로 출력되므로 다시 오브젝트화 시켜줘야 한다.

JSON.parse()을 통해 오브젝트로 바꿔준다.

응용

만약 상품을 클릭하면 최근본상품의 블록에 그 상품에 대한 정보가 나오게 하고 싶다면?
즉, a상품을 클릭하고, c상품 클릭, b상품을 클릭하면 최근 본 상품에는 a,c,b 차례대로 순서에 맞게 출력되야 한다.
상품을 클릭하기 위해서는 a상품을 클릭 후 상품이 정렬된 페이지로 이동 후 다시 b상품을 클릭하는 식의 차례를 따라야 한다. 이때, 브라우저는 자동적으로 새로고침이 이루어지고, 다음 상품을 클릭했을 때에는 그 전에 보았던 상품에 대한 데이터는 사라지게 된다. 따라서 서버를 통해 상품 방문에 대한 기록을 데이터화해야 하고, 서버가 없는 지금 상황에서 localStorage라는 임시공간을 이용해보자는 것이다.

대략적인 UI 구성은 다음과 같다.

  1. 유저가 상품을 클릭하여 상품에 대한 디테일 페이지로 들어간다.
  2. 이때 localSotorage에 있는 데이터를 꺼내오는 과정이 이루어진다.
    (만약 클릭한 것이 첫 상품이라면 당연히 데이터는 없을 것이다.)
  3. 꺼내온 데이터는 JSON형식으로 "[]" 과 같이 출력되므로 따옴표를 제거한다.
  4. 그리고 꺼내온 배열형식의 데이터 공간에 현재 상품에 대한 id값을 push 해준다.
  5. 만약 push하려는 상품이 이전에도 방문한 상품이라면 그 배열에 존재하는 데이터이므로 중복을 제거해 준다.
  6. 마지막으로 저장된 배열 데이터 공간을 다시 localStorage에 넣어준다.
  1. 페이지로 들어가는 경우는 컴포넌트가 실행되거나 업데이트되는 경우와 같으므로 useEffect()를 이용하자.
//Detail함수 내부
useEffect( ()=>{
}, [] );
  1. 'watched'라는 key 값을 가진 배열 데이터를 꺼내자.
//Detail함수 내부
useEffect( ()=>{
  var arr = localStorage.getItem('watched');
}, [] );
  1. 꺼내온 배열을 JSON.parse를 통해 배열화 시켜주자.
//Detail함수 내부
useEffect( ()=>{
  var arr = localStorage.getItem('watched');
  arr = JSON.parse(arr);
}, [] );
  1. 배열에 id 값을 push하자.
useEffect( ()=>{
  var arr = localStorage.getItem('watched');
  arr = JSON.parse(arr);
  arr.push(id);
}, [] );
  1. 배열에서 중복되는 데이터는 제거하자.
useEffect( ()=>{
  var arr = localStorage.getItem('watched');
  arr = JSON.parse(arr);
  arr.push(id);
  arr = new Set(arr); //Set이라는 함수를 새로운 객체로 선언
  arr = [...arr]; // 다시 원래의 arr에 깊은 복사
}, [] );
  1. 마지막으로 다시 localStorage에 저장
//Detail함수 내부
useEffect( ()=>{
  var arr = localStorage.getItem('watched');
  arr = JSON.parse(arr);
  arr.push(id);
  arr = new Set(arr);
  arr = [...arr];
  localStorage.setItem('watched', JSON.stringify(arr) );
}, [] );

상품을 클릭하면 상품에 대한 id값이 배열에 차례대로 저장된다.

좋은 웹페이지 즐겨찾기