[React] 19. localStorage로 최근 본 상품 기능 구현

지렁·2023년 11월 20일
0
post-custom-banner

기존 문제점

새로고침하면 state 데이터는 모두 리셋된다

브라우저는 파일들을 처음부터 다시 읽기 때문이다

🎈해결법

  • 서버로 state 데이터를 보내 DB 저장
  • localStorage 사용


localStorage

정보를 저장할 수 있는 공간으로 크롬개발자 도구에서 Application 탭에서 확인 가능하며 유저가 브라우저 청소를 하지 않는 이상 영구적으로 남아있다

  • 사이트마다 5MB 정도의 문자 데이터를 저장 가능
  • key/value 형태로 저장
  • 사이트를 재접속해도 남아있다 (브라우저 청소 시 삭제됨)

📢 localStoarge랑 비슷한 sessionStorage는 휘발성이라 브라우저 끄면 정보가 날아간다


🖤 사용법

◾ 데이터 저장

문자 형태만 저장 가능

localStorage.setItem('key','value')

◾ 데이터 출력

localStoarge.getItem('key')

◾ 데이터 삭제

localStorage.removeItem('key')

🖤 array/object 저장법

원래 로컬스토리지에는 문자만 저장 가능하기 때문에 배열/객체가 저장이 되지 않는다

👌 그렇다면

문자취급을 해주는 JSON 형태로 바꾸면 된다 !
그리고 꺼내서 사용하려면 다시 object/array로 바꿔주면 된다 !

array/object ➡ JSON

JSON.stringify()

array/object ➡ JSON

JSON.parse()
// 객체 저장
let obj= {name:'lee'}
localStorage.setItem('data',JSON.stringify(obj))
// 꺼내서 객체 사용
let data= JSON.parse(localStorage.getItem('data'))
console.log(data)

🖤 최근 본 상품 기능 구현

mount 시에만 한번 동작하는 useEffect 기능을 이용하여 'watched'라는 key에 빈 배열을 만들어준다

function App() {

  useEffect(()=>{
    localStorage.setItem('watched',JSON.stringify([]))
  },[])

그리고 onClick 속성을 이용하여 클릭 한 상품의 제목을 localStorage에 저장을 해주었고,
2번 이상 클릭한 상품은 추가시키지 않는 조건문을 달았다

function Card({data}){
  return(
    <>
      {data.map((item,i)=>(
        <Col key={i} xs={4} onClick={()=>{
          let watched= JSON.parse(localStorage.getItem('watched'))
          if(!watched.some((i)=>i===item.title)){
            watched.push(item.title)
            localStorage.setItem('watched',JSON.stringify(watched))
          }         
        }}>

🖤 최근 본 상품 UI 만들기

위처럼 App에 작성을 하다가 최근 본 상품 UI는 대부분 Detail 페이지에 존재한다는 것이 떠올랐다
그래서 조금이라도 깔끔하게 작성하기 위해 Detail 페이지에서 작업을 하였다

export function Detail({data}){
  ...
  let [watchedItem,setWatchedItem] = useState(localStorage.getItem('watched'))

  useEffect(()=>{
    let watched= JSON.parse(localStorage.getItem('watched'))
    const isIdDuplicate = watched.some(item => item.id === id);
     // 중복되지 않으면 watched에 새로운 객체 추가
    if (!isIdDuplicate) {
      watched.push({
        id: id,
        title: data[id].title,
        image: `https://codingapple1.github.io/shop/shoes${Number(id) + 1}.jpg`
      });
      watched= Array.from(watched)
      localStorage.setItem('watched',JSON.stringify(watched))
      setWatchedItem(JSON.stringify(watched))}
    },[])

최근 본 상품 UI를 만들기 위해서는 title 뿐만이 아닌 id,image 도 필요하다
그래서 객체 형태로 push 하였다

[{},{},...] 꼴의 자료에서 중복확인하기?

객체 형태로 존재하는 배열에서 이미 존재하는 상품이니?를 확인하기 위해 Set을 사용해보았지만... 도무지 해결법이 떠오르지 않아 조건문을 사용하였다ㅠㅠ


◾ UI

<div className='my-5'>
        <p><b> 최근 본 상품 </b></p>       
        <Row>
        {JSON.parse(watchedItem).slice(-4).map((item,i)=>     
        <Col key={i} xs={3} >
            <Link to={`/detail/${item.id}`}>
            <img src={item.image} alt="img" width="40%" />
            <h4>{item.title}</h4>
           </Link>
          </Col>
        )}
        </Row>
      </div>

마지막 4개의 상품만 뜨도록 하기 위해 slice 매소드를 사용하였다
-4 는 뒤에서 4개라는 뜻!

그리고 watchedItem은 문자형태이기 때문에 배열 매소드 map을 사용하기 위해 파싱을 해주었다


⚠ 문제 발생

localStorage의 watched는 보존되어야 하는데 메인 페이지로 이동할 때마다 값이 초기화가 된다

function App() {
  useEffect(()=>{
      localStorage.setItem('watched',JSON.stringify([]))
    }
  },[])

처음에 mount 될 때 빈배열을 만들어주라고 코드를 작성했었기 때문!!


👏 새로고침 시 초깃값으로 돌아가는거 방지

그래서 초기에 watch에 빈배열 만들어준 useEffect 부분에서 값이 없을 때만 빈배열 만들어주라는 조건문을 추가하였다

function App() {

  useEffect(()=>{
    //새로고침 시 초깃값으로 돌아가는거 방지
    if(!localStorage.getItem('watched')){
      localStorage.setItem('watched',JSON.stringify([]))
    }
  },[])

profile
공부 기록 공간 🎈💻
post-custom-banner

0개의 댓글