React 조건부 렌더링 카드가 다시 뜨는 이유
고르기·건너뛰기 버튼만 달았더니, 카드를 무시하고 그냥 질문한 사람에게 카드가 매번 다시 나타났다
화면에 카드를 하나 띄우고 「나중에 할게요」 버튼을 달았다고 하자. 그 사람이 버튼을 누르지 않고 그냥 하던 일을 계속하면, 코드에서는 무슨 일이 일어나나. 대개 아무 일도 안 일어난다.
2026-08-09, 전시 관람 서비스의 AI 도슨트에 「연령대 눈높이」를 붙였다. QR을 찍고 들어오면 채팅방 위에 카드가 뜬다.
먼저 나이대를 알려주시겠어요?
초등학생중·고등학생20~40대50대 이상그냥 바로 물어볼게요
고르면 그 뒤 답변의 어휘와 문장 길이가 맞춰진다. 안 고르고 싶으면 「그냥 바로 물어볼게요」를 누르면 된다. 카드는 한 번만 뜨고 사라진다 — 그렇게 설계했고 컴포넌트 주석에도 그렇게 적었다.
{!ageAsked && <AgeBandPrompt
onPick={(band) => { setAgeBand(band); setAgeAsked(true); }}
onSkip={() => setAgeAsked(true)} />}
고르면 끝. 건너뛰면 끝. 깔끔해 보였다.
리뷰에서 걸린 지점
관람객이 카드를 무시하고 그냥 질문을 입력하면
ageAsked를 아무도 안 바꾼다. 답변이 오고 로딩이 끝나는 순간 카드가 답변 바로 밑에 다시 나타난다. 화면은 자동으로 맨 아래로 스크롤되니까 관람객 눈에 정확히 걸린다. 세 번 물으면 세 번 본다.
내가 센 건 버튼 두 개였다. 고르기, 건너뛰기.
그런데 사용자가 이 질문에 답하는 방법은 셋이었다.
- 고른다
- 건너뛰기를 누른다
- 무시하고 자기 할 일을 한다
3번이 제일 흔한 행동인데, 그건 내 화면에 버튼이 없다. 그래서 안 세어졌다.
상태를 무엇으로 바꾸는가
여기서 갈리는 건 이 질문이다.
- UI 이벤트로 바꾸면 — 내가 만든 버튼만큼만 경로가 생긴다
- 의미가 끝나는 시점으로 바꾸면 — 버튼이 없는 경로도 잡힌다
「연령대를 물었나?」라는 상태가 진짜로 끝나는 시점은 버튼을 누를 때가 아니다. 대화가 시작될 때다. 첫 질문이 날아간 순간, 물어볼 타이밍은 이미 지났다.
그래서 플래그를 켜는 자리를 버튼에서 메시지 전송 함수로 옮겼다.
const submitMessage = async (raw, clicked) => {
const text = raw.trim();
if (!text || thinking) return;
// 질문을 보내는 순간 묻는 시점은 지났다 —
// 카드를 무시하고 그냥 물어본 것도 대답이다.
setAgeAsked(true);
...
한 줄이다. 그런데 이 한 줄이 세 번째 경로를 통째로 덮는다. 버튼을 하나 더 만드는 게 아니라, 상태의 정의를 「눌렀나」에서 「그 시점이 지났나」로 바꾼 것이다.
겉모습이 같은데 규칙이 다른 카드
같은 화면에 비슷한 게 하나 더 있었다. 가입 권유 카드는 「나중에 할게요」를 눌러야 사라진다. 그건 그대로 뒀다. 그 카드는 무시하고 대화를 이어가도 계속 있어야 맞기 때문이다.
둘 다 채팅방 위에 뜨는 카드고 둘 다 「나중에」 버튼이 있는데, 하나는 「물어보는 것」이고 하나는 「권하는 것」이라서 규칙이 달랐다.
화면에 「나중에」 버튼을 달 때 한 번 볼 만하다. 아무것도 안 누르고 그냥 하던 일을 하는 경로가 코드에 있는가. 그게 맞는 화면도 있고, 아닌 화면도 있다.