state 보존과 리셋 — 트리 위치와 key prop · 퀴즈

7 문항 · Bloom: Understand:2, Apply:2, Analyze:3 · v1.0.0

Q1 Understand mcq_single

React가 컴포넌트 state를 추적하는 기준에 대한 설명으로 가장 정확한 것은?

정답: C
React는 컴포넌트 인스턴스가 아니라 '같은 부모 안 같은 자식 슬롯 + 같은 컴포넌트 타입'을 기준으로 state를 보존한다. 위치가 바뀌거나 타입이 달라지면 state는 파괴된다.
오답 해설:
  • A. 흔한 오해: state가 JS 객체에 매여 있다고 생각하지만, React는 매 렌더마다 컴포넌트 함수를 호출해 새 객체를 만든다. 추적 단위는 트리 위치다.
  • B. props는 추적 기준이 아니다. 같은 위치·같은 타입이면 props가 바뀌어도 state는 그대로 보존된다.
  • D. React는 인스턴스에 UUID를 붙이지 않는다. 명시적 identity를 주려면 개발자가 key prop을 써야 한다.
Q2 Analyze mcq_single

다음 코드에서 isFancy 값이 true ↔ false 로 바뀔 때 Counter의 count state는 어떻게 되는가? ```jsx function App({ isFancy }) { return ( <div> {isFancy ? ( <Counter isFancy={true} /> ) : ( <Counter isFancy={false} /> )} </div> ); } ```

정답: C
삼항 분기로 두 JSX가 보이지만 트리에서는 둘 다 div의 첫 번째 자식이며 컴포넌트 타입도 동일한 Counter다. 따라서 같은 위치 + 같은 타입 규칙으로 state는 보존된다. JSX 소스 위치와 트리 위치는 다르다.
오답 해설:
  • A. props 변경은 state 리셋 트리거가 아니다. React는 props 값으로 추적하지 않는다.
  • B. JSX 소스 코드의 줄 번호는 무관하다. 트리 위치만 본다.
  • D. 삼항 연산자 자체가 타입을 바꾸지 않는다. 양쪽 분기 모두 Counter 타입이다.
Q3 Analyze mcq_single

다음 코드에서 isFancy 값이 바뀌면 Counter의 state는 어떻게 되며, 그 이유는? ```jsx function App({ isFancy }) { return ( <div> {isFancy ? ( <div><Counter /></div> ) : ( <section><Counter /></section> )} </div> ); } ```

정답: B
트리에서 외부 div의 첫 번째 자식이 한 번은 div, 다른 한 번은 section이다. 같은 위치의 컴포넌트 타입이 바뀌면 React는 그 서브트리 전체를 파괴하고 다시 만든다. Counter 자체가 같다는 것은 의미가 없다 — 부모가 사라지면 자식도 함께 사라진다.
오답 해설:
  • A. Counter 동일성만 보면 안 된다. 그 위 부모(div/section)가 같은 슬롯에서 타입을 바꿨다.
  • C. 부모 타입이 같은 위치에서 바뀌면 그 안의 모든 state가 파괴된다.
  • D. 조건부 렌더가 항상 리셋시키는 것은 아니다 — Q2처럼 같은 부모·같은 타입이 유지되면 보존된다.
Q4 Apply mcq_single

연락처 목록에서 선택된 contact가 바뀔 때마다 ChatForm의 입력값을 자동으로 비우려고 한다. key prop을 어디에 두는 것이 올바른가? ```jsx function Messenger({ contact }) { return ( <div> <ContactInfo contact={contact} /> <ChatForm /* (?) */ /> </div> ); } ```

정답: B
key는 부모가 자식을 렌더할 때 그 자식 element에 붙여 '같은 위치라도 다른 정체성'임을 알린다. contact가 바뀔 때 ChatForm을 새 인스턴스로 보고 state(입력값)를 리셋하려면 ChatForm 호출부에 key={contact.id}를 둔다. key는 같은 부모(div) 안에서만 유일하면 된다.
오답 해설:
  • A. input 엘리먼트에 key를 달아도 ChatForm 자체가 같은 인스턴스로 유지되므로 ChatForm이 들고 있는 useState는 리셋되지 않는다.
  • C. Messenger에 key를 달면 contact prop을 바꿔주는 더 위 부모가 Messenger 전체를 리셋한다 — 의도(ChatForm만 리셋)와 어긋나며 ContactInfo의 state까지 파괴된다.
  • D. key는 컴포넌트 정의가 아닌 element(JSX 호출)에 다는 prop이다.
Q5 Analyze mcq_single

다음 중 컴포넌트 정의 중첩(nested component definition) 안티패턴을 보여주는 코드는?

정답: A
A는 Parent가 렌더될 때마다 Child 함수가 새로 만들어진다. React 입장에서 매번 다른 컴포넌트 타입이므로 같은 위치라도 state가 매 렌더 리셋된다. 해법은 B처럼 Child를 top-level로 옮기는 것. C(핸들러를 안에 정의), D(map+key)는 정상 패턴이다.
오답 해설:
  • B. 정상 — Child가 모듈 top-level이라 매 렌더 동일 타입을 유지한다.
  • C. 함수 정의를 안에 두는 것 자체는 문제 없다. 안티패턴은 '컴포넌트(JSX를 반환하는 함수)' 정의를 중첩할 때만 발생한다.
  • D. .map + key는 권장 패턴이다.
Q6 Apply mcq_multi

같은 위치의 컴포넌트 state를 의도적으로 리셋하는 올바른 전략을 모두 고르시오. (정답 2개)

정답: A, B
공식 두 전략은 (1) 다른 위치에서 렌더, (2) 같은 위치에 key 부여다. C는 props mirroring 안티패턴(S2에서 다룸), D는 nested definition 안티패턴이라 우연히 리셋이 일어날 뿐 의도된 도구가 아니다. E는 동기화 로직과 부수효과로 버그가 늘어나며 권장되지 않는다.
오답 해설:
  • C. 안티패턴 — 첫 렌더 외에는 prop 변화가 state에 반영되지 않거나 동기화 버그를 만든다.
  • D. 리셋이 부작용으로 일어나지만 매 렌더 타입이 새로 생겨 성능·식별성 모두 망가진다. 의도된 도구가 아니다.
  • E. 선언형 패턴이 아닌 명령형 동기화로, 무한 루프·중복 렌더 등의 버그를 부른다.
Q7 Understand short_answer

다음 코드에서 showHint 토글 시에도 Form의 입력값(state)이 보존되는 이유를 '트리 위치 규칙'으로 두 문장 이상 설명하시오. JSX 소스에서 Form이 두 군데에 따로 적혀 있는데도 왜 같은 위치로 인식되는지 포함할 것. ```jsx function App({ showHint }) { if (showHint) { return ( <div> <p>Hint: ...</p> <Form /> </div> ); } return ( <div> <Form /> </div> ); } ```

정답 예시: 'React는 JSX의 소스 코드 위치가 아니라 렌더 트리에서의 위치(부모와 자식 슬롯)로 state를 추적한다. 두 분기 모두 결과적으로 div의 마지막 자식 슬롯에 Form 컴포넌트를 렌더하므로, 같은 부모·같은 슬롯·같은 타입 조건이 만족돼 state가 보존된다.' 의도적으로 리셋하려면 분기를 다른 부모로 가르거나 <Form key=...>를 부여해야 한다.채점 기준:
  • 1점: 'React는 JSX 소스 위치가 아니라 렌더 트리 위치로 state를 추적한다'는 핵심 명제를 진술.
  • 1점: 두 분기 모두 동일 부모(div) + 동일 슬롯 위치 + 동일 컴포넌트 타입(Form) 조건이 만족된다고 명시.
  • 1점(보너스): 의도적 리셋 방법(다른 부모로 분기 또는 key prop)을 한 가지 이상 언급.