포켓몬 도감 사이트) TroubleShooting 1 : Detail 페이지와 이벤트 버블링🎈

밍갱·2025년 2월 5일
0

PROJECTS

목록 보기
7/20

1. 문제 발생🤯

01. Query params를 사용한 디테일 페이지 기능 도전

오늘 도전해 볼 기능은 Query params를 통한 동적 라우팅이다. 강의를 통해 path에 동적 라우팅을 주는 방법을 배웠지만, 이번 과제에서 queryString, 즉 Query params을 연습해볼 예정이다.
강의에 없던 내용이므로, 구글링과 챗gpt에게 받은 힌트를 기반으로 기능을 구현해보았다.

2. 개념 정리🧐

00. url과 url 구조

URL(Uniform Resource Locators)은 웹에서 HTML 페이지, CSS 문서, 이미지 등 리소스의 위치를 나타내는 주소를 뜻한다. 즉, 웹 페이지를 찾기위한 주소이다. URL은 보통 Protocol, Domain, Path, Parameter, Fragment로 이루어져 있다.

이미지 출처 ▶️ URL에 대한 정리가 잘되어있으니 나중에 정독해보기!

01. Query params란?

Query params는 요청하는 URL에 부가 정보를 포함해, 서버가 추가적인 동작을 수행할 수 있도록 도와준다
Path 뒤에 ? 물음표와 함께 붙는 키-값(key-value) 쌍으로 구성되어 있으며, key=value 로 표현한다. 값(value)에는 문자열 뿐만 아니라 숫자, 리스트 등 다양한 형태의 데이터를 넣을 수 있다. 또한, & 앰퍼샌드를 사용하여 여러 개의 Query params를 하나의 문자열로 전달한다.

Query params 참고 사이트 1
Query params 참고 사이트 2

02. Query params 적용하기

  • 라우트 컴포넌트 : Query params는 URL에 부가적인 정보를 포함하는 것이므로 라우터 컴포넌트에도 특별한 설정은 필요없다.
  • 링크 역할 컴포넌트(Link 컴포넌트 또는 onClick 등) : 쿼리스트링이 포함된 주소를 전달한다.
//라우트 컴포넌트
<Route path="/detail" element={<Detail />} />

//링크 역할 컴포넌트
const CardWrapper = (props) => {
	//useNavigate로 query params 전달
	const navigate = useNavigate();
	const goToDetail = (props.id) => {
    	navigate(`/detail?id=${props.id}`);
	};

	//<CardLi> = 링크 역할 컴포넌트
	return <CardLi onClick={() => goToDetail(props.id)}>
}

03. Query params 가져오기 + 관련 Hook

컴포넌트에서 현재 위치(url)의 query params(쿼리 문자열)에 대한 데이터를 읽고 수정할 수 있다.

  • useLocation : 현재의 Location에 포함된 여러 가지 정보를 담은 객체를 반환한다. 하지만 Query params의 value만 뽑아서 사용하려면 별도의 작업을 해야 하므로 복잡하다.
import { useLocation } from "react-router-dom"

// 컴포넌트 안에서 데이터를 변수에 담고 확인
const location = useLocation();
console.log(location.search); //?sort=popular
  • useSearchParams : useLocation의 단점을 보완한 Hook으로, useState와 유사한 방식으로 선언하고 사용할 수 있다.
import { useSearchParams } from "react-router-dom"

const [searchParams, setSearchParams] = useSearchParams();

searchParams는 value를 읽어오거나 변경하는 여러 메서드를 제공한다.
값을 읽어오는 메서드

메서드의미
searchParams.get(key)특정한 key의 value를 가져오는 메서드
(value 가 2개 이상이라면 첫번째 value 만 리턴)
searchParams.getAll(key)특정 key 에 해당하는 모든 value 를 가져오는 메서드
searchParams.toString()쿼리 스트링을 string 형태로 리턴

값을 변경하는 메서드

메서드의미
searchParams.set(key, value)인자로 전달한 key 값을 value 로 설정
기존에 값이 존재했다면 그 값은 삭제
searchParams.append(key, value)기존 값을 변경하거나 삭제하지 않고 추가하는 방식

Query params Hook 참고 사이트 1

3. 해결 방안😇

01. 기능 구현

우선 PokemonDetail.jsx을 생성하였다. 디자인은 잠시 내려두고, 구성요소만 넣어주었다.
( DetailWrapper는 styled-components이다. )

그리고 Router.jsx에서 path와 element를 연결해주었다. 위에서 언급했듯이, 라우터 컴포넌트에 특별한 설정은 필요없기 때문에 path는 "/detail"로 설정해주었다.

PokemonCard를 클릭하면, Query params을 통한 동적 라우팅이 되어야한다. Query params는 id 값으로 설정하고, useNavigate를 사용하여 라우팅되도록 코드를 작성하였다.

한번 카드를 클릭해보자.

잘 구현된다!

01-1. 이벤트 버블링 문제 발생

앗! 추가 버튼을 클릭했더니, 카드를 클릭했을 때처럼 디테일 페이지로 이동하는 문제가 생겼다. 원인을 열심히 구글링해본 결과, "이벤트 버블링"으로 인해 발생한 문제였다.

*이벤트 버블링이란? : 한 요소에서 발생한 이벤트는 먼저 해당 요소의 핸들러를 실행한 후, 부모 요소로 이벤트가 전파되며 부모 요소의 핸들러도 실행된다. 가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작한다.

버블링 참고 사이트

02. stopPropagation()으로 버블링 해결

이벤트 버블링 문제는 event.stopPropagation()을 사용해 간단히 해결할 수 있다. 만약 이를 사용하지 않으면, 버튼을 클릭했을 때도 PokemonCard의 onClick이 실행되어 원치 않는 페이지 이동이 발생할 수 있다.

특히 PokemonCard는 PokemonList.jsxDashBoard.jsx에서 사용되며, 각 컴포넌트에서 onClick으로 전달되는 로직이 다르다. 따라서 PokemonCard 내부에서 stopPropagation()을 처리하는 대신, 이벤트를 관리하는 PokemonList와 DashBoard에서 event.stopPropagation()을 적용해 버블링을 방지했다.

Button에 넘겨줄 onClick에 event.stopPropagation()을 함께 넘겨주었다.

4. 결과😎

01. 해결!

02. 최종 코드

  • PokemonDetail.jsx

  • Router.jsx

  • PokemonList.jsx

  • PokemonCard.jsx

profile
미술 전공에서 프론트엔드 개발까지

0개의 댓글