새로고침하면 state 데이터는 모두 리셋된다
브라우저는 파일들을 처음부터 다시 읽기 때문이다
정보를 저장할 수 있는 공간으로 크롬개발자 도구에서 Application 탭에서 확인 가능하며 유저가 브라우저 청소를 하지 않는 이상 영구적으로 남아있다
- 사이트마다 5MB 정도의 문자 데이터를 저장 가능
- key/value 형태로 저장
- 사이트를 재접속해도 남아있다 (브라우저 청소 시 삭제됨)
문자 형태만 저장 가능
localStorage.setItem('key','value')
localStoarge.getItem('key')
localStorage.removeItem('key')
원래 로컬스토리지에는 문자만 저장 가능하기 때문에 배열/객체가 저장이 되지 않는다
문자취급을 해주는 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))
}
}}>
위처럼 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을 사용해보았지만... 도무지 해결법이 떠오르지 않아 조건문을 사용하였다ㅠㅠ
<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([]))
}
},[])