상황
- 사용자가 상품을 클릭하면 최근에 클릭한 상품의 순서대로 최근 본 상품이라는 단어 아래에 해당 상품들을 출력하고 싶었습니다.
해결방법
현재 ItemMain이라는 컴포넌트에서 위의 정보들을 보여주고 있습니다. 여기서 상품들을 api를 통해 호출하고 state배열에 저장한다음 return문 안에서 상품들을 map을 이용해 보여주고 있습니다.
그래서 이미 호출한 state배열을 활용하고자 했습니다. 최근본상품의 컴포넌트를 호출할때 props로 상품들(state배열)을 전달하고 해당 컴포넌트의 useEffect문 안에서 findIndex함수를 통해 상품의 정보를 배열에 저장해주고 출력해주었습니다. 간단하게 순서대로 설명해보면
1. 메인페이지를 접속할때 localStorage에 wathced 배열 생성.
2. 상품을 클릭할때 localstorage에 배열안에 해당 상품 id 저장.
3. 최근본상품 컴포넌트의 useEffect에서 findIndex함수를 통해 해당 상품의 id의 상품들을 저장하고 출력.
1. 첫번째로 메인페이지를 접속할때 localStorage에 watched 배열 생성입니다.
if문을 이용해 null 이면 로컬에 배열을 생성해주었습니다.
useEffect(() => {
//최근본상품 localstorage할당
//최근본상품이 없으면 생성
let localarray = localStorage.getItem('watched');
if (localarray == null) {
localStorage.setItem('watched', JSON.stringify([]));
}
}, [])
2. 두번째로 상품을 클릭할때 localStorage에 배열로 해당 상품 id 저장입니다.
아래의 코드는 상품을 클릭할때 실행되는 컴포넌트의 useEffect 코드입니다.
watched라는 배열을 getItem함수로 꺼낸후 json형식이기때문에 변환을 해주어야합니다.
unshift함수를 이용해 배열의 맨 앞에 id를 넣어주었습니다. push를 사용하지 않고 unshift를 사용한 이유는 배열의 맨앞에서부터 상품들을 출력하고 싶어서 맨앞에 값을 넣어주었습니다.
그리고 2번실행되어 2번저장되는 현상을 막기위해 set함수를 사용한뒤 setItem으로 저장해줍니다.
useEffect(() => {
//상품한개정보
fetchPostInfo();
//최근본상품
let output = localStorage.getItem('watched');
output = JSON.parse(output);
output.unshift(id);
output = new Set(output);
output = Array.from(output);
localStorage.setItem('watched',JSON.stringify(output));
}, [])
메인에서 컴포넌트 호출 코드입니다.
컴포넌트를 호출할때 메인에서 호출한 상품들의 정보들이 담긴 state배열을 props로 전달해줍니다.
<div className='Main-Content'>최근 본 상품</div>
<Watched store={store}/>
3. 최근본상품 컴포넌트의 useEffect에서 findIndex함수를 통해 해당 상품의 id의 상품들을 저장하고 출력.
먼저, local스토리지에 값이 있는지 없는지 체크해줍니다. 값이 없는데 값들을 불러오면 오류가 발생할 수 있습니다.
그다음 json형식이기 때문에 변환을 해주고 변환된 배열을 map으로 돌면서 각각에 맞는 상품들의 정보를 push로 임시배열에 넣어주고
map 함수가 끝나면 setstate 함수를 사용해 저장해주었습니다.
(저는 메인에서 최근본상품을 3개만 보여줄거기 때문에 index<3이라는 if문을 작성했습니다, 앞에서부터 3개의 값들에 대한 상품의 정보가 담겨야 하기 때문)
useEffect(() => {
let localarray = localStorage.getItem('watched');
//localStorage watche에 상품들의 id가 존재하면
if (localarray) {
setWatched(null);
localarray = JSON.parse(localarray);
let copy = [];
//해당 상품의 정보를 copy에 unshift로 앞에서 부터 넣는다.
localarray.map((a, index) => {
let itemindex = 0;
if (index < 3) {
itemindex = props.store.findIndex(item => Number(item.id) == Number(a))
console.log(itemindex);
//local저장소의 watche에는 unshift로 넣는게 맞는데 여기서는 push를 해주어야 앞의 값부터 나오기때문에.
//copy.unshift(props.store[itemindex]);
copy.push(props.store[itemindex]);
}
})
//copy를 state 배열에 저장해준다.
setWatched(copy);
}
}, [])
이제 watched(state 배열)에 담긴 요소들을 return 문안에서 출력만 해주면 됩니다.
저같은 경우는 메인 화면에 상품들을 표시해주는 컴포넌트를 재활용해주었습니다.
//최근본상품은 3개의 상품만 보여주기 때문에 아래와 같이 설정.
const currentPosts = () => {
let currentPosts = 0;
currentPosts = watched.slice(0, 3);
return currentPosts;
};
if (!watched) return null;
return (
<div className='Item-Wrap'>
{/* currentPosts에 위의 watched에 담긴 상품들을 전달 */}
<Posts currentPosts={currentPosts()} />
</div>
)
결과화면
처음 들어왔을때 로컬스토리지의 값입니다. 아무것도 없습니다.
상품을 클릭했을때 값들이 local에 잘 저장이 됩니다.
다른 상품을 클릭했을때 배열의 앞으로 삽입이 됩니다.
메인에서 확인해보면 상품들도 잘 출력되는 것을 확인할 수 있습니다.
계속해서 위의 아이스크림을 클릭해보겠습니다.
여기서 다른 상품을 하나 클릭해보겠습니다. 앞으로 값이 잘 들어가고 메인에서도 상품이 잘 출력됩니다.
마주했던 문제들
- 최근본상품 컴포넌트안에 useEffect의 로직을 메인컴포넌트의 useEffect안에서 작성하려고 했던점 : api를 호출하여 state배열에 값을 할당하기전에 로직이 실행되어 오류가 발생 -> 새로운 컴포넌트를 만들어 해결
'프론트엔드 > react' 카테고리의 다른 글
왜 react-query ? (3) | 2023.12.03 |
---|---|
React - Carousel설계 ( useRef ) (1) | 2023.11.26 |
리액트 - 서버에서 받은 UTC시간을 KST로 변환 (0) | 2023.09.15 |
React - navigate로 props전달방법 (0) | 2023.09.09 |
React - useEffect에서 axios.get을 이용해 받은 데이터로 요소생성 (0) | 2023.09.09 |