미친 React key
발행: (2026년 2월 15일 오후 11:42 GMT+9)
4 분 소요
원문: Dev.to
Source: Dev.to
map을 통한 렌더링
예시 1
export function Parent() {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => [6, 7, 8, 9, 10, ...prev]);
}, 3000);
}, []);
return (
<>
{array.map((item) => (
))}
);
}
export function Child({ item }: { item: number }) {
console.log(item);
return <>{item};
}
실험 결과: 1 2 3 4 5
예시 2
export function Parent() {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => [6, 7, 8, 9, 10, ...prev]);
}, 3000);
}, []);
return (
<>
{array.map((_, index) => (
))}
);
}
실험 결과: 6, 7, 8, 9, 10, 1, 2, 3, 4, 5
예시 3
export function Parent() {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => [
...prev.slice(0, 2),
10,
...prev.slice(3, prev.length),
]);
}, 3000);
}, []);
return (
<>
{array.map((item) => (
))}
);
}
export function Child({ item }: { item: number }) {
return <>{item};
}
실험 결과: 10
실험 1
- 초기 상태:
[1, 2, 3, 4, 5] → [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
| memo 사용 여부 | key | 렌더링 결과 |
|---|---|---|
| 사용 안 함 | item | 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 |
| 사용 안 함 | index | 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 |
사용 (React.memo) | item | 6, 7, 8, 9, 10 |
사용 (React.memo) | index | 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 |
실험 2 (값 교체)
- 초기 상태:
[1, 2, 3, 4, 5] → [1, 2, 10, 4, 5]
| memo 사용 여부 | key | 렌더링 결과 |
|---|---|---|
| 사용 안 함 | item | 1, 2, 10, 4, 5 |
| 사용 안 함 | index | 1, 2, 10, 4, 5 |
사용 (React.memo) | item | 10 |
사용 (React.memo) | index | 1, 2, 10, 4, 5 |
결론 (실험 1·2)
React.memo를 사용하면 같은 key에 대해 props가 변하지 않으면 자식 컴포넌트는 재렌더링되지 않는다.React.memo를 사용하지 않으면 부모가 리렌더링될 때마다 자식도 항상 리렌더링된다.
실험 3 (배열 순서 변경과 상태 유지)
export function Parent() {
const [array, setArray] = useState([1, 2, 3]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => prev.toReversed());
}, 3000);
}, []);
return (
<>
{array.map((item) => (
))}
);
}
export function Child({ item }: { item: number }) {
const [text, setText] = useState("");
return (
<>
{item}th textfield:
setText(e.target.value)} />
);
}
결과
key={item}사용 시: 배열 순서가 뒤바뀌어도 각 컴포넌트의 상태가 올바르게 매핑되어 순서가 바뀐 값과 함께 유지된다.key={index}사용 시: 순서가 바뀌어도 state가 index와 매핑되므로 입력값이 잘못된 위치에 남아 순서 변경이 정상적으로 반영되지 않는다.
최종 결론
index를 key로 사용하는 것은 가능하지만, 배열 순서가 변할 가능성이 있는 경우에는 사용하면 안 된다.- key는 컴포넌트 인스턴스와 상태를 연결하는 역할을 하므로, 고유하고 변하지 않는 값(
item등)을 사용해야 상태가 올바르게 유지된다.