React | alert 창이 두 번씩 떴던 오류...

하영·2024년 8월 24일
1

React

목록 보기
11/17

숙련주차 개인과제를 하면서 alert 기능을 넣었는데 원하는대로 구현이 되지 않았다. 조금 어이없는 실수(?)였는데 똑같은 실수를 하지 않으려고.. 정리해보았다.


01. 구현해야할 기능

카드 6장이 선택된 상태에서 또 <추가> 버튼을 누르면 alert을 띄우는 것이었다.

🚧 작성한 코드

import styled from "styled-components";
import { useContext } from "react";
import { PokemonContext } from "../context/PokemonContext.jsx";

const Dashboard = () => {
  const { selectedPokemon, removePokemon } = useContext(PokemonContext);

  if (selectedPokemon.length >= 6) {
    alert("최대 6개까지만 선택할 수 있습니다.");
    //return; >> 을 쓰면 계속 경고창이 떴음
  }

  return (
    <DashboardContainer>
      <h2>나만의 포켓몬</h2>
      {selectedPokemon.length === 0 ? (
        <p>포켓몬을 선택해주세요.</p>
      ) : (
        <DashboardCardBox>
          {selectedPokemon.map((pokemon) => (
            <DashboardCard key={pokemon.id}>
              <img src={pokemon.img_url} />
              {pokemon.korean_name}
              <Button onClick={() => removePokemon(pokemon.id)}>삭제</Button>
            </DashboardCard>
          ))}
        </DashboardCardBox>
      )}
    </DashboardContainer>
  );
};

export default Dashboard;

02. 발생한 문제점

  • 7번째 카드를 선택하면 경고창이 뜨는건 성공했지만 경고창이 2번씩 뜸
  • 경고창을 닫으면 7번째 카드는 추가가 되면 안 되는데 추가가 됨
  • 얼리리턴을 사용해보고자 마지막에 return을 쓰니까 경고창이 반복적으로 뜸

03. 문제에 대한 고민과 해결

  • selectedPokemon 이라는 State가 값이 변하면서 리렌더링이 되면서 경고창이 2번 떴나?
  • 버튼을 눌렀을 때! 경고창이 떠야하니까 Card 컴포넌트 onClick에 경고창 함수를 넣어주어야 할까?
  • Context로 리팩토링하고 처음 onAdd 함수 만들 때 조건문 넣어보자! > 해결

🚧 수정한 코드

import { createContext, useState } from "react";

export const PokemonContext = createContext(null);

export function PokemonProvider({ children }) {
  const [selectedPokemon, setSelectedPokemon] = useState([]);

  const addPokemon = (pokemon) => {
    if (selectedPokemon.length >= 6) {
      alert("최대 6개까지만 선택할 수 있습니다.");
      return; 
      // 여기서는 return 써도 ㄱㅊ... 
      // 조건문 없애고 경고창만 띄우거나 App.jsx 수정
      // 추가되는 시점(버튼을 누르는 이벤트를 만드는 곳)에 로직을 작성해야함
    }

    if (!selectedPokemon.some((item) => item.id === pokemon.id)) {
      setSelectedPokemon([...selectedPokemon, pokemon]);
    } else {
      alert("이미 선택한 포켓몬 입니다.");
      return;
    }
  };

  const removePokemon = (pokemonId) => {
    const filteredPokemon = selectedPokemon.filter((item) => {
      return item.id !== pokemonId;
    });
    setSelectedPokemon(filteredPokemon);
  };

  return (
    <PokemonContext.Provider
      value={{
        selectedPokemon,
        setSelectedPokemon,
        addPokemon,
        removePokemon,
      }}
    >
      {children}
    </PokemonContext.Provider>
  );
}

04. 내가 생각한 이유가 맞았을까?

해결은 했지만 정확한 이유를 알지 못해서 튜터님께 여쭤보았다.

1. alert 창이 2번씩 떴던 이유

main.jsx 파일에 가면 볼 수 있는데 react는 StrictMode, 즉 엄격모드 로 실행된다. StrictMode는 개발 중에 컴포넌트에서 일반적인 버그를 빠르게 찾을 수 있도록 한다.
이것 때문에 우리가 콘솔창을 확인할 때도 늘 2번씩 찍혔던 것이다.
따라서 내가 넣은 alert창도 이 StrictMode 때문에 2번씩 나왔던 것이다.

Strict Mode를 잠깐 정리하고 가면 아래의 기능을 담당한다.

🔍 Strict Mode?

  • 컴포넌트가 순수하지 않은 렌더링으로 인한 버그를 찾기 위해 추가로 다시 렌더링 한다.
  • 컴포넌트가 Effect 클린업이 누락되어 발생한 버그를 찾기 위해 Effect를 다시 실행한다.
  • 컴포넌트가 더이상 사용되지 않는 API를 사용하는지 확인한다.

2. 경고창이 뜨기만 하고 카드 추가를 막은 로직이 안 먹은 이유

if (selectedPokemon.length >= 6) {
      alert("최대 6개까지만 선택할 수 있습니다.");
      return; 

우선 해당부분 코드만 보면 선택된 (추가된) 카드의 개수가 6개 이상이면! 경고창이 뜨면서 아래의 함수를 return으로 종료시키는 것이다.
이 경고창을 뜨게 하는건 사용자가 <추가>버튼을 "클릭한 그 시점" 에 위 코드의 조건문을 검사한 후 실행해야한다.

하지만 나는 버튼 클릭이벤트가 없는 Dashboard 컴포넌트에서 뜬금없이 넣어버린 것이다.

const Dashboard = () => {
  const { selectedPokemon, removePokemon } = useContext(PokemonContext);

if (selectedPokemon.length >= 6) {
      alert("최대 6개까지만 선택할 수 있습니다.");
      return; 
  
  //조건문 없이 경고창만 써도 2번씩 뜨는 현상은 동일하게 발생
  //버튼 클릭하는 이벤트 생성하는 곳에 alert 조건문을 넣어야한다!

버튼 클릭과는 연관이 없고 그냥 카드 개수만 영향을 받게 되니까 if문을 지우고 경고창만 넣어도 똑같은 오류가 생긴다

05. 결론

⭐️ 구현하려는 이벤트가 "어느 시점"에서 실행되어야 하는지 생각하고 코드를 작성하자!


✅ 추가버튼 코드

const addPokemon = (pokemon) => {
    if (selectedPokemon.length >= 6) {
      alert("최대 6개까지만 선택할 수 있습니다.");
      return; 
    }

    if (!selectedPokemon.some((item) => item.id === pokemon.id)) {
      setSelectedPokemon([...selectedPokemon, pokemon]);
    } else {
      alert("이미 선택한 포켓몬 입니다.");
      return;
    }
  };

Dashboard에 있는 카드가 추가되고 없어지니까 당연히 경고창도 여기서 뜨게 하는게 맞다고 아주 단순한 생각으로 작성해버렸다...ㅎ (정리하고나니까 더 창피)
그래도 리액트가 StrictMode 기능으로 검사를 하고 있고 이러한 모든 검사는 개발 전용이며 프로덕션 빌드에는 영향을 미치지 않는다는 솔솔한 정보도 알았다.


여전히 실수 가득한 초보자지만 많이 실수하고 배워나가자..!!🚀🚀

profile
왕쪼랩 탈출 목표자의 코딩 공부기록

2개의 댓글

comment-user-thumbnail
2024년 8월 26일

당신은 Strict모드가 필요할 수 있습니다

1개의 답글