091
[JS/React] 리스트와 키, 입력 폼 본문
1. 리스트와 키
- 리스트(List)란 같은 종류의 아이템을 순서대로 모아 놓은 것으로, 자바스크립트에서는 배열로 표현합니다.
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map(number =>
<li>{number}</li>
);

-> Array.map()을 사용할 때 key 없이 사용하면 위처럼 "Each child in a list should have a unique key prop"라는 경고가 뜹니다. 렌더링은 되지만 성능 최적화가 안된다는 의미입니다.
- 키(key)가 필요한 이유는 React는 Virtual DOM 비교 시 리스트 아이템이 변경/추가/삭제되었는지 파악해야합니다. key가 없으면 React는 전체 리스트를 다시 렌더링 하고, key가 있으면 변경된 항목만 업데이트합니다.(성능 최적화) 키의 유효범위는 같은 리스트 안에서만 고유하면 됩니다.
- 키 값 설정하는 법
(1) 배열의 내부 값인 숫자/문자 값을 키로 설정하기: 배열에 중복값이 있을 수 있어 권장하지 않습니다.
numbers.map(number =>
<li key={number.toString()}>
{number}
</li>
);
(2) 고유 id를 키로 설정하기(권장)
const todos = [
{ id: 1, text: '첫 번째 할일' },
{ id: 2, text: '두 번째 할일' },
];
todos.map(todo =>
<li key={todo.id}>
{todo.text}
</li>
);
(3) 인덱스를 키로 설정하기: 아이템 순서가 바뀌거나 추가/삭제가 있어나면 버그가 발생할 수 있으므로 id가 없을 때만 사용합니다.
todos.map((todo, index) =>
<li key={index}>
{todo.text}
</li>
);
2. 폼(forms)
- 폼(Forms)은 사용자로부터 입력을 받기 위한 UI요소로, HTML 기본 폼과 React 폼은 작동방식이 다릅니다.
(1)input 차이
<form>
<label>
이름:
<input type="text" name="name" />
</label>
<button type="submit">제출</button>
</form>
-> HTML 폼은 각 엘리먼트(input, textarea, select)가 내부적으로 자체 state를 가지며, 이를 DOM이 관리합니다.
const [value, setValue] = useState('');
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
-> 컴포넌트의 state가 모든 입력 값을 관리하며, React가 데이터의 단일 진실 공급원(single source of truth)이 됩니다.
(2) textarea: 사용자가 여러 줄의 텍스트를 입력할 수 있는 텍스트 입력 영역을 정의할 때 사용합니다.(출저:https://www.tcpschool.com/html-tags/textarea)
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
<textarea>
내용이 children으로 들어감
</textarea>
<textarea
value={value}
onChange={handleChange}
/>
-> React에서 textarea는 value 속성을 사용해 단일 태그로 사용할 수 있어 input과 사용방식이 통일됩니다.
(3) select
<select>
<option value="apple">사과</option>
<option selected value="banana">바나나</option>
</select>
const [value, setValue] = useState('grape');
<select
value={value}
onChange={(e) => setValue(e.target.value)}
>
<option value="apple">사과</option>
<option value="banana">바나나</option>
<option value="grape">포도</option>
</select>
-> React는 select 태그의 selected 속성 대신 최상위 select에 value 속성을 사용합니다. input, textarea, select 모두 value + onChange 패턴으로 통일됩니다.
- React에서 input, textarea, select를 제어 컴포넌트(controlled component)로 사용한다. 사용자가 입력할 때마다 onChange 이벤트로 state를 업데이트하고, 그 state가 다시 Input의 value로 연결됩니다.
-> 제어 컴포넌트를 통해 입력 초기값을 설정하거나 입력을 강제변환(소문자->대문자), 한 입력값 변경 시 다른 필드 값이 자동으로 변경되거나 유효성을 검사하거나 제출 버튼 활성/비활성 제어 등이 가능합니다.
-> event.target은 이벤트가 발생한 DOM 엘리먼트를 가리킵니다. event.target.value는 input의 혐재 입력값, event.target.checked는 checkbox의 체크여부를 의미합니다. event.preventDefault()는 form submit나 a같은 페이지 이동을 하는 태그를 사용할 때 이동을 차단하기 위해 꼭 작성해줘야합니다.
+) 입력 값 무조건 대문자로
import React, { useState } from "react";
export default function NameForm() {
const [value, setValue] = useState('');
const handleChange = (event) => {
//setValue(event.target.value);
setValue(event.target.value.toUpperCase());
};
const handleSubmit = (event) => {
alert(`입력한 이름: ${value}`);
event.preventDefault(); // 페이지 새로고침 방지
};
return (
<form onSubmit={handleSubmit}>
<label>
이름:
<input
type="text"
value={value}
onChange={handleChange}
/>
</label>
<button type="submit">제출</button>
</form>
);
}
- 비제어 컴포넌트(uncontrolled component)는 ref를 사용해 DOM에서 직접 값을 읽는 방식을 말하며, React에서는 state로 모든 것을 관리하는 제어 컴포트를 권장하지만, 파일 업로드(input type="file")는 읽기 전용이라 항상 비제어 방식을 써야합니다.
+) 회원가입 컴포넌트
import React, { useState } from "react";
export default function SignUp(props) {
const [name, setName] = useState("");
const [gender, setGender] = useState("남자");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [birthdate, setBirthdate] = useState("");
const [isEssential, setIsEssential] = useState(false);
const handleChangeName = (event) => {
setName(event.target.value);
};
const handleChangeGender = (event) => {
setGender(event.target.value);
};
const handleChangeEmail = (event) => {
setEmail(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
if(name.trim() === ""){
alert("이름을 입력해주세요.");
} else if(email.trim() === ""){
alert("이메일을 입력해주세요.");
} else if(!isEssential){
alert("약관에 동의해주세요.");
} else {
alert("가입이 완료되었습니다.");
}
};
return (
<form onSubmit={handleSubmit}>
<label>
이름:
<input type="text" value={name}
onChange={handleChangeName} />
</label>
<br />
<label>
성별:
<select value={gender}
onChange={handleChangeGender}>
<option value=
"남자">남자</option>
<option value=
"여자">여자</option>
</select>
</label>
<br />
<label>
이메일:
<input type="email" value={email}
onChange={handleChangeEmail} />
</label>
<br />
<label>
비밀번호:
<input type="password" value={password}
onChange={(e)=>{setPassword(e.target.value)}} />
</label>
<br />
<label>
생년월일:
<input type="date" value={birthdate}
onChange={(e)=>{setBirthdate(e.target.value)}} />
</label>
<br />
<label>
<input type="checkbox" checked={isEssential}
onChange={(e)=>{setIsEssential(e.target.checked)}} />
[필수] 약관에 동의합니다
</label>
<br />
<button type="submit">가입</button>
</form>
);
}'Programming Language > JavaScript&TypeScript' 카테고리의 다른 글
| [JS/React] 리액트 라우터(React Router) (0) | 2026.05.24 |
|---|---|
| [JS/React] 이벤트 핸들링 & 조건부 렌더링 (0) | 2026.04.12 |
| [JS/React] JSX(4): Lifecycle, Hook (0) | 2026.04.12 |
| [JS/React] JSX(3): Component 실습, State (0) | 2026.04.12 |
| [JS/React] JSX(2): Component, Element (1) | 2026.04.10 |
