2023.02.01 textarea,select 등
HTML에서 <textarea> 엘리먼트는 텍스트를 children으로 정의합니다.
<textarea>
Hello there, this is some text in a text area
</textarea>
React에서 <textarea>는 value 어트리뷰트를 대신 사용합니다.
이 방식은 앞에서 배운 제어 컴포넌트 방식인데 값을 컴포넌트의 state를 사용해서 다룰 수 있습니다.
이렇게하면 <textarea>를 사용하는 폼은 한 줄 입력을 사용하는 폼과 비슷하게 작성할 수 있습니다.
import { useState } from "react";
function RequestForm(props) {
const [value, setValue] = useState('요청사항을 입력하세요.');
const handleChange = (event) => {
setValue(event.target.value);
}
const handleSubmit = (event) => {
alert('입력한 요청사항: ' + value);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
요청사항:
<textarea value={value} onChange={handleChange} />
</label>
<button type="submit">제출</button>
</form>
)
}
위 코드는 고객으로부터 요청사항을 입력받기 위한 RequestForm이라는 컴포넌트입니다.
state로 value가 있고, 이 값을 <textarea> 태그의 value라는 attribute에 넣어줌으로써 화면에 나타나게 됩니다.
여기에서는 value를 선언할 때 초깃값을 넣어줬기 때문에 처음 렌더링될 때부터 <textarea>에 텍스트가 나타나게 됩니다.
HTML에서 <select>는 드롭다운 목록을 만듭니다.
드롭다운 목록은 여러 가지 옵션 중에서 하나를 선택할 수 있는 기능을 제공합니다.
HTML에서는 <option> 태그를 <select>태그가 감싸는 형태로 사용합니다.
예를 들어, 이 HTML은 과일 드롭다운 목록을 만듭니다.
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
selected 라는 attribute를 갖고 있습니다.
이것은 현재 Coconut이 선택되어 있는 상태라는 것을 알 수 있습니다.
React에서는 selected 어트리뷰트를 사용하는 대신 최상단 select태그에 value 어트리뷰트를 사용합니다.
한 곳에서 업데이트만 하면되기 때문에 제어 컴포넌트에서 사용하기 더 편합니다.
아래는 예시입니다.
import { useState } from "react";
function FruitSelect(props) {
const [value, setValue] = useState('greape');
const handleChange = (event) => {
setValue(event.target.value);
}
const handleSubmit = (event) => {
alert('Your favorite flavor is: ' + value);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
Pick your favorite flavor:
<select value={value} onChange={handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<button type="submit">submit</button>
</form>
);
}
위 코드에는 FruitSelect라는 컴포넌트가 있고 이 컴포넌트의 state로 grape라느 초깃값을 가진
value가 하나 있습니다.
그리고 이 값을 <select> 태그에 value로 넣어 주고 있습니다.
값이 변경된 경우에는 위와 마찬가지로 handleChange( ) 함수에서 setValue()함수를 사용하여
값을 업데이트합니다.
이 방식을 사용하게 되면 사용자가 옵션을 선택했을 때 value라는 하나의 값만을 업데이트하면 되기 때문에 더 편리합니다.
만약 목록에서 다중으로 선택이 되도록 하려면 아래와 같이 multiple이라는 속성값을 true로 하고,
value로 선택된 옵션의 값이 들어있는 배열을 넣어 주면 됩니다.
<select multiple = {true} value = {['B', 'C']}>
전반적으로 <input type="text">, <textarea> 및 <select> 모두 매우 비슷하게 동작합니다.
모두 제어 컴포넌트를 구현하는데 value 어트리뷰트를 통해서 값을 전달하고
값을 변경할 때는 onChange에서 setValue() 함수를 사용하여 값을 업데이트합니다.
이러한 방식은 실제로 사용자가 입력을 받는 컴포넌트를 만들 때 사용하기 때문에 잘 기억하기 바랍니다.
//input 태그
<input type="text" value={value} onChange={handleChange} />
// textarea 태그
<textarea value={value} onChang={handleChange} />
// select 태그
<select value={value} onChange={handleChange}>
<option value="apple">사과</option>
<option value="banana">바나나</option>
<option value="grape">포도</option>
<option value="watermelon">수박</option>
</select>
디바이스의 저장 장치로부터 사용자가 하나 또는 여러개의 파일을 선택할 수 있게 해주는 HTML 태그입니다.
보통은 서버로 파일을 업로드하거나 자바스크립트의 File API를 사용해서 파일을 다룰 때 사용합니다.
HTML에서 <input type="file">는 사용자가 하나 이상의 파일을 자신의 장치 저장소에서 서버로 업로드하거나 File API를 통해 JavaScript로 조작할 수 있습니다.
<input type="file" />
값이 읽기 전용이기 때문에 React에서는 비제어 컴포넌트(Uncontrolled Component)입니다.
지금까지는 하나의 컴포넌트에서 하나의 입력만을 다뤘는데 만약 하나의 컴포넌트에서 여러개의 입력을 다루기 위해서는 어떻게 해야 할까요?
이런 경우에는 여러 개의 state를 선언하여 각각의 입력에 대해 사용하면 됩니다.
아래는 예시입니다.
import { useState } from "react";
function Reservation(props) {
cosnt [havaBreakfast, setHaveBreakfast] = useState(true);
const [numberOfGuest, setNumberOfGuest] = useState(2);
const handleSubmit = (event) => {
alert(`아침식사 여부 : ${havaBreakfast}, 방문객 수 : ${numberOfGuest}`);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
아침식사 여부:
<input
type="checkbox"
checked={havaBreakfast}
onChange={(event) => {
setHaveBreakfast(event.target.checked);
}}/>
</label>
<br />
<label>
방문객 수:
<input
type="number"
value={numberOfGuest}
onChange={(event) => {
setNumberOfGuest(event.target.value);
}} />
</label>
<button type="submit">submit</button>
</form>
)
}
위 코드는 Reservation이라는 이름을 가진 호텔 예약을 위한 컴포넌트인데
예약을 하기 위해 필요한 정보 두 가지를 입력받도록 되어 있습니다.
하나는 아침식사 선택 여부이고, 다른 하나는 방문객 수입니다.
아침식사 선택 유무를 입력받기 위한 <input>태그 type이 checkbox로 되어 있고,
값이 변경되면 setHaveBreakfast() 함수를 통해 값을 업데이트합니다.
그리고 방문객 수를 입력받기 위한 <input>태그는 type이 number로 되어 있고,
값이 변경되면 setNumberOfGuest()함수를 통해 값을 업데이트합니다.
클래스 컴포넌트에서는 setState()함수 하나로 모든 state의 값을 업데이트했지만
함수 컴포넌트에서는 각 state의 변수마다 set 함수가 따로 존재하기 때문에 위와 같은 형태로 각각의 set함수를 사용해서 구현하면 됩니다.
제어 컴포넌트에 value prop을 지정하면 의도하지 않는 한 사용자가 변경할 수 없습니다.
만약 value prop은 넣되 자유롭게 입력할 수 있게 만들고 싶다면 값에 undefined 또는 null을 넣어주면 됩니다.
아래 코드가 이것을 보여줍니다. (첫 번째 입력은 잠겨있지만 잠시 후 입력이 가능해집니다.)
ReactDOM.render(<input value="hi" />, rootNode);
setTimeout(function() {
ReactDOM.render(<input value={null} />, rootNode);
}, 1000);
처음에는 input의 값이 hi로 정해져 있어서 값을 바꿀수 없는 입력 불가 상태였다가
timer에 의해 1초 뒤에 value가 null인 <input>태그가 렌더링되면서 입력 가능한 상태로 바뀝니다.
이러한 방법을 잘 활용하면 value prop을 넣으면서 동시에 사용자가 자유롭게 입력할 수 있게 만들 수 있습니다.
데이터를 변경할 수 있는 모든 방법에 대해 이벤트 핸들러를 작성하고 React 컴포넌트를 통해 모든 입력 상태를 연결해야 하기 때문에 때로는 제어 컴포넌트를 사용하는 게 지루할 수 있습니다.
특히 기존의 코드베이스를 React로 변경하고자 할 때나 React가 아닌 라이브러리와 React 애플리케이션을 통합하고자 할 때 짜증날 수 있습니다.
이러한 경우에 입력 폼을 구현하기 위한 대체 기술인 비제어 컴포넌트를 확인할 수 있습니다.
유효성 검사, 방문한 필드 추적 및 폼 제출 처리와 같은 완벽한 해결을 원한다면 Formik이 대중적인 선택 중 하나입니다.
그러나 Formik은 제어 컴포넌트 및 state 관리에 기초하기 때문에 배우는 걸 쉽게 생각하면 안 됩니다.
import { useState } from "react";
function SignUP(props) {
const [name, setName] = useState("");
const handleChangeName = (event) => {
setName(event.target.value);
};
const handleSubmit = (event) => {
alert(`이름: ${name}`);
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<label>
이름:
<input type="text" value={name} onChange={handleChangeName} />
</label>
<button type="submit">제출</button>
</form>
);
}
export default SignUP;
위 컴포넌트는 이름을 입력할 수 있는 <input>태그와 입력된 값을 저장하기 위한 name이라는 state를 갖고 있습니다. 단순한 형태의 입력 양식 컴포넌트입니다.
수정후 npm start
브라우저에 이름을 입력할 수 있는 입력 양식이 나오게 됩니다.
그리고 입력 양식에 이름을 입력하고 제출 버튼을 누르면 아래 그림과 같이 대화 상자가 뜨고
그 안에 방금 입력한 이름이 들어가 있는 것을 볼 수 있습니다.
이름과 함께 성별을 입력 받을 수 있도록 만들어 보겠습니다.
gender라는 이름의 state가 추가되었고 성별을 입력받기 위한 <select> 태그가 추가되었습니다.
<select>태그에는 총 두 가지 옵션이 들어가 있는데,
<select>태그의 값이 변경되면 이를 처리하기 위해 handleChangeGender()라는 이벤트 핸들러를 만들어 사용하고 있습니다.
import { useState } from "react";
function SignUP(props) {
const [name, setName] = useState("");
const [gender, setGender] = useState("남자");
const handleChangeName = (event) => {
setName(event.target.value);
};
const handleChangeGender = (event) => {
setGender(event.target.value);
};
const handleSubmit = (event) => {
alert(`이름: ${name}, 성별: ${gender}`);
event.preventDefault();
};
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>
<button type="submit">제출</button>
</form>
);
}
export default SignUP;
이름 작성과 성별을 선택할 수 있다.