리스트(List)
:같은 아이템을 순서대로 모아놓은 것
키(Key)
:각 객체나 아이템을 구분할 수 있는 고유한 값(두 리스트 사이에선 키가 같아도 상관없음)
Array.map() 활용하여 여러개의 컴포넌트 랜더링
: 배열에 모든 요소에 대해 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환
const numbers = [1,2,3,4,5];
const listItems = numbers.map(number =>
<li>{number}</li>
);
리스트 출력하는 컴포넌트
./components/NumberList.jsx
import React from "react";
export default function NumberList(props) {
const { numbers } = props;
const listItems = numbers.map( number =>
<li>{number}</li>
);
return (
<ul> {listItems} </ul>
);
}
./index.js
import NumberList from './components/NumberList'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<NumberList numbers={ [1, 2, 3, 4, 5] } />
</React.StrictMode>
);
*실행시 경고문이 출력되는데 , 현재 각 아이템에 키가 없기 때문임
키 값으로 숫자의 값을 사용
const numbers = [1,2,3,4,5];//배열 요소 중복 가능서 있음
const listItems = numbers.map(number =>
<li> key = {numbber.toString()}>{number}</li>
);
키 값으로 id를 사용하는 방식(아이템의 고유한 id가 있을 경우 사용)
const todos = [
{id:1, text: '첫 번째 할일'},
{id:2, text: '두 번쨰 할일'}
]
const todoItems = todos.map(todo =>
<li key = {todo.id}>{todo.text}</li>
);
키 값으로 인덱스를 사용하는 방법 - 아이템의 고유한 id가 없을 경우 사용
map() 메서드 안에 있는 엘리먼트는 key가 필수
const todos = [
{ text: '첫 번째 할일'},
{ text: '두 번쨰 할일'}
]
const todoItems = todos.map(todo, index) =>
<li key = {index}>{todo.text}</li>
);
실습) 출석부 만들기
import React from "react";
const students = [
{
id:1,
name: "Inje",
},
{ id:2,
name: "Steve",
},
{ id:3,
name: "Bill",
},
];
export default function AttenanceBook(props){
return(
<ul>
{students.map((student, index) => {
return<li key = {student.id}>
{student.name}</li>
})}
</ul>
);
}
폼(Forms)
:사용자로부터 입력을 받기 위해 사용하는 양식
리액트는 컴포넌트 내부에서 state를 통해 데이터를 관리
제어 컴포넌트(Controlled Component)
React에 의해서 값이 제어되는 컴포넌트 (input form element)
제어 컴포넌트를 사용하면 입력값이 리액트 컴포넌트의 state를 통해 관리할 수 있음
사용자의 입력을 직접적으로 제어할 수 있음
function NameForm(props) {
const[value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value); //event객체->event.target: 이벤트가 발생한 타겟
}
const handleSubmit = (event_ => {
alert(`입력한 이름 : ${vlaue}`);
event.preventDefault();
}//event.preventDefault();->새로운 페이지로 연결되는 기본 동작 중단시킴
return(
<form onSubmit = {handleSubmit}>
<label>
이름:
<input type = "text" value = {value} onChange = {handleChange} />
</label>
<button type = "submit" >제출 </button>
</form>
)
}
textarea 태그
• 여러 줄의 텍스트를 입력 받기 위한 HTML 태그
• 리액트 – textarea 태그의 value 라는 속성을 사용하여 텍스트를 표시
<label>
요청사항:
<textarea value = {value} onChange = {handleChange}/>
</label>
select 태그
• drop-down 목록을 보여주기 위한 HTML 태그
리액트 – selected 대신 value 속성을 사용하여 선택 값을 표시
// FruitSelect라는 이름의 React 함수 컴포넌트를 정의합니다.
// 이 컴포넌트는 props라는 매개변수를 받지만, 현재 코드에서는 사용하지 않습니다.
function FruitSelect(props) {
// useState 훅을 사용하여 'value'라는 상태 변수를 선언하고,
// 초기값을 'grape' (포도)로 설정합니다.
// value는 현재 선택된 과일의 값을 저장합니다.
// setValue는 value 상태를 업데이트하는 함수입니다.
const [value, setValue] = React.useState('grape'); // React.useState로 명시적으로 사용
// select 박스의 값이 변경될 때 호출되는 함수입니다.
const handleChange = (event) => {
// 이벤트 객체(event)를 통해 현재 선택된 select option의 value를 가져와서
// setValue 함수를 사용하여 value 상태를 업데이트합니다.
// 오타가 있어서 event.targegt.value -> event.target.value 로 수정했습니다.
setValue(event.target.value);
}
// 폼 제출(submit) 이벤트가 발생했을 때 호출되는 함수입니다.
// 오타가 있어서 handleSubit -> handleSubmit 로 수정했습니다.
const handleSubmit = (event) => {
// 현재 value 상태에 저장된 과일 값을 사용하여 경고창을 띄웁니다.
alert(`선택한 과일: ${value}`);
// 폼의 기본 제출 동작(페이지 새로고침 등)을 막습니다.
event.preventDefault();
}
// 컴포넌트가 렌더링할 JSX(JavaScript XML)를 반환합니다.
return(
// 폼(form) 엘리먼트를 생성하고, 제출 이벤트(onSubmit)가 발생하면
// 위에서 정의한 handleSubmit 함수를 호출하도록 설정합니다.
<form onSubmit = {handleSubmit}>
{/* 레이블 엘리먼트를 생성합니다. */}
<label>
과일을 선택하세요:
{/* select 엘리먼트를 생성합니다. */}
{/* value 속성은 현재 select 박스에 표시될 값을 value 상태 변수와 연결합니다. */}
{/* onChange 속성은 select 박스의 값이 변경될 때 handleChange 함수를 호출하도록 설정합니다. */}
<select value = {value} onChange = {handleChange}>
{/* 옵션 엘리먼트들입니다. 각각 과일의 값과 표시될 텍스트를 정의합니다. */}
<option value = "apple"> 사과</option>
<option value = "banana"> 바나나</option>
<option value = "grape"> 포도</option>
</select> {/* select 엘리먼트 닫는 태그가 빠져있어서 추가했습니다. */}
</label>
{/* 제출(submit) 버튼을 생성합니다. */}
<button type = "submit"> 제출</button>
</form>
)
}
// 이 컴포넌트를 다른 파일에서 사용할 수 있도록 내보냅니다. (예: export default FruitSelect;)
// 실제 사용 시에는 이 컴포넌트를 렌더링하는 코드가 필요합니다.
// 예: ReactDOM.render(<FruitSelect />, document.getElementById('root'));
• multiple inputs
• 여러 개의 state를 선언하여 각각의 입력에 대해 사용
Input Null Value
• 제어 컴포넌트에서 value 값을 지정하되 입력 값을 자유롭게 변경하고자 할 때
• 제어 컴포넌트에 value 값이 정해지면 입력값을 바꿀 수 없음
• value에 undefined 또는 null을 넣어 주면 입력이 가능한 상태로 변경할 수 있음
실습)) 회원가입 폼 만들기
./components/SignUpORg.jsx
import React, { useState } from "react";
// 컴포넌트 정의: 회원가입 폼
export default function SignUp() {
// 각 입력 필드의 상태(state) 정의
const [name, setName] = useState(""); // 이름
const [gender, setGender] = useState("남자"); // 성별 (기본값: 남자)
const [email, setEmail] = useState(""); // 이메일
const [password, setPassword] = useState(""); // 비밀번호
const [birthdate, setBirthdate] = useState(""); // 생년월일
const [agree, setAgree] = useState(false); // 약관 동의 체크 여부
const [error, setError] = useState(""); // 에러 메시지 상태
const [emailValid, setEmailValid] = useState(true); // 이메일 유효성 여부
// 이메일 형식을 정규표현식으로 검사하는 함수
const validateEmail = (email) => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email); // 정규표현식에 맞으면 true, 아니면 false 반환
};
// 이메일 입력 시마다 호출되는 함수 (실시간 유효성 검사)
const handleEmailChange = (e) => {
const value = e.target.value;
setEmail(value); // 입력된 이메일 값을 상태에 저장
setEmailValid(validateEmail(value)); // 이메일 유효성 검사 결과 저장
};
// 폼 제출 시 실행되는 함수
const handleSubmit = (event) => {
event.preventDefault(); // 폼의 기본 제출 동작을 막음
// 필수 입력 항목 확인
if (!name) {
alert("이름을 입력해주세요");
return;
}
if (!validateEmail(email)) {
alert("이메일 주소가 유효하지 않습니다");
return;
}
if (!agree) {
alert("약관에 동의해주세요");
return;
}
// 모든 조건이 만족되었을 때 실행
setError(""); // 에러 메시지 초기화
alert(`이름: ${name}\n이메일: ${email}\n성별: ${gender}\n생년월일: ${birthdate}`);
};
// 실제로 사용자에게 보여지는 폼 구성
return (
<form onSubmit={handleSubmit}>
<h2>회원가입</h2>
{error && <p style={{ color: "red" }}>{error}</p>} {/* 에러 메시지 표시 */}
<label>
이름:
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
</label>
<br />
<label>
성별:
<select value={gender} onChange={(e) => setGender(e.target.value)}>
<option value="남자">남자</option>
<option value="여자">여자</option>
</select>
</label>
<br />
<label>
이메일:
<input type="email" value={email} onChange={handleEmailChange} />
{!emailValid && (
<p style={{ color: "red", marginTop: 0 }}>
유효한 이메일 주소를 입력해주세요.
</p>
)}
</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={agree} onChange={(e) => setAgree(e.target.checked)} />
약관에 동의합니다.
</label>
<br />
<button type="submit">가입</button>
</form>
);
}
이메일 유효성 검사 정규 표현식
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@ 앞뒤로 문자 존재 여부
도메인에 . 포함 여부 검사
공백 또는 잘못된 기호는 허용하지 않음
코드 흐름 요약
- 사용자가 입력 폼에 정보를 입력
- useState 훅을 통해 각 항목의 값이 상태로 저장됨
- 이메일 입력 시 handleEmailChange 함수로 유효성 실시간 검사
- 가입 버튼 클릭 시 handleSubmit 함수 실행
- 이름/이메일/약관 동의 항목에 대해 유효성 검사
- 문제 없으면 alert()으로 정보 출력
'React' 카테고리의 다른 글
훅(Hook) (0) | 2025.04.15 |
---|---|
컴포넌트와 Props (0) | 2025.04.02 |
리액트JSX (0) | 2025.03.25 |
소프트웨어 설계 3주차 (1) | 2025.03.18 |
소프트웨어 설계 2주차 (1) | 2025.03.18 |