React를 이용하여 네이버 지도에 텃밭들을 표시하고, 텃밭에서 찜하기 버튼을 누르면 해당 텃밭을 찜하는 기능을 구현하고 있었다.
리액트 컴포넌트에서 garden?.gardenLikeId
를 기반으로 isGardenLiked
상태가 계산되며, 이는 사용자가 정원을 "좋아요" 했는지 여부를 나타내고 있는 상황이다. 이 값에 따라 '찜하기' 버튼의 상태가 변경되어야 하는데, liked
라는 내부 상태가 초기에 한 번 설정된 후 자동으로 업데이트되지 않아 isGardenLiked
와 liked
의 값이 일치하지 않는 문제가 발생했다.
const MapGardenDetailBottomSection = ({
garden,
refetch,
}: MapGardenDetailBottomSectionProps) => {
const [loading, setLoading] = useState<boolean | undefined>(undefined);
// isGarenLiked 값과 liked 상태값이 다른 이슈가 발생함.
const isGardenLiked = garden?.gardenLikeId === 0 ? false : true;
const [liked, setLiked] = useState(isGardenLiked);
const { isOpen, onOpen, onClose } = useDisclosure();
const [copied, setCopied] = useState(false);
const [isMobile, setIsMobile] = useState<boolean | null>(null);
const [isClickedCallInWeb, setIsClickedCallInWeb] = useState(false);
const { mutateLikeGarden } = useLikeGarden(liked, garden?.gardenId, setLiked);
// 생략...
const handleClickLike = () => {
setLoading(true);
if (liked)
mutateLikeGarden({ type: 'cancel', gardenLikeId: garden?.gardenLikeId });
else mutateLikeGarden({ type: 'like', gardenLikeId: garden?.gardenLikeId });
setTimeout(() => {
refetch();
setTimeout(() => {
setLoading(false);
}, 150);
}, 250);
};
return (
// 생략...
);
};
export default MapGardenDetailBottomSection;
이 문제의 원인은 리액트 상태 관리의 특성에서 기인하였다. 리액트에서는 상태가 변경되면 해당 상태에 의존하는 컴포넌트의 리렌더링이 트리거된다. 그러나, 상태 초기화는 컴포넌트가 마운트될 때 단 한 번만 발생하며, 이후에는 상태 업데이트 함수를 호출하지 않는 한 기존 상태가 유지된다. useState
로 선언된 liked
상태는 외부에서 gardenLikeId
가 변경되어도 자동으로 업데이트되지 않기 때문에, isGardenLiked
의 변경이 liked
에 반영되지 않는 것이었다.
이 문제를 해결하기 위해 useEffect
를 사용하여 gardenLikeId
의 변경을 감지하고, 이에 따라 liked
상태를 업데이트하는 방법을 구현했다. useEffect
내에서 gardenLikeId
를 의존성 배열로 설정하여, 해당 값이 변경될 때마다 liked
상태를 적절히 업데이트하도록 했다.
// 추가
useEffect(() => {
setLiked(isGardenLiked);
}, [isGardenLiked]);
리액트 컴포넌트가 리렌더링 될 때 변수와 상수의 값들은 초기화가 된다. 이 초기화된 상수(isGardenLiked)를 liked 상태의 초기값으로 할당해주고 있어서.. 당연히 liked 상태의 값이 초기화된 isGardenLiked값으로 업데이트가 될줄 알았다. 하지만 이것은 나의 큰 오해였다. 해결방안으로, 수동으로 useEffect를 이용해서 isGardenLiked의 값이 변할때마다 liked 상태를 업데이트 해주는 것으로 간단하게 문제를 해결해 줄 수 있었다.
리액트에서 useEffect
는 컴포넌트의 생명주기 동안 의존성 배열 값의 변화에 대응하여 내부 상태를 업데이트할 수 있는 강력한 hook이다. 이 사례를 통해 useEffect
를 적절히 사용하면 상태 관리 로직을 보다 효율적으로 만들고, UI의 일관성과 반응성을 향상시킬 수 있음을 확인할 수 있었다. 이러한 패턴은 리액트 애플리케이션에서 자주 발생하는 문제에 대한 해결책을 제공하며, 효과적인 사용자 경험을 구현하는 데 중요한 역할을 한다.