👉 HTML 폼 컨트롤 요소(<input />, <textarea>, <select> 등)
는 사용자의 입력 콘텐츠를 자체적으로 관리한다. JavaScript를 사용해 각 컨트롤의 value 값을 확인하면 사용자가 입력한 콘텐츠에 접근할 수 있다.
✍ Exmple
const inputEmail = document.querySelector('#email')
// GET: HTML 폼 컨트롤 속성 값 읽기
console.log(inputEmail.value)
// SET: HTML 폼 컨트롤 속성 값 쓰기
inputEmail.value = 'songsong2920@gmail.com'
👉 React는 컴포넌트 상태 정보를 state 속성으로 관리하며 setState() 메서드를 사용해 상태를 업데이트(교체) 한다.
✍ Exmple
// React Component
class BaseInput extends Component {
// 컴포넌트 상태
state = {
content: ''
};
// 컴포넌트 메서드(이벤트 리스너)
handleInput = (e) => {
// 컴포넌트 상태(업데이트)
this.setState({
content: e.target.value
});
}
// 컴포넌트 렌더 라이프 사이클 훅
render() {
return (
<label>
{ this.props.label }
<input
type={this.props.type}
value={this.state.content}
onChange={e => this.handleInput(e)} />
</label>
);
}
}
// React Element
const baseEmailInput = <BaseInput type="email" label="이메일" />
👉 폼을 렌더링 하는 React 컴포넌트는 폼에서 발생되는 사용자의 입력 값을 컨트롤 한다. 이러한 방식으로 React에 의해 값이 컨트롤 되는 입력 폼 요소는 컨트롤 컴포넌트(Controlled Component) 이다.
<input>
Control👉 HTML From (<input> 포함)
을 React에 의해 컨트롤 되는 컴포넌트로 변경할 수 있다.
✍ Exmple (HTML Form)
<form onsubmit="onSubmitHandler">
<label>
@이메일: <input type="email" name="email" />
</label>
<button>전송</button>
</form>
✍ Exmple (React Controlled Component)
class EmailForm extends Component {
state = {
email: ''
};
handleInput = (e) => {
this.setState({
email: e.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
console.log(`입력하신 이메일 ${this.state.email}이 성공.`);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
@이메일 :
<input
type="email"
name="email"
value={this.state.email}
onChange={e => this.handleInput(e)} />
</label>
<button>전송</button>
</form>
)
}
👉컨트롤 컴포넌트로 사용하면 모든 state
의 업데이트는 연관된 이벤트 리스너(컴포넌트 메서드) 의해 처리된다. 컨트롤 컴포넌트를 통해 사용자의 입력 내용을 업데이트 하거나 유효성 검사하는 것이 가능하다. 입력 내용의 앞/뒤에 공백을 제거하고 싶다면 리스너 코드를 아래와 같이 수정한다.
✍ Exmple
handleInput = (e) => {
this.setState({
email: e.target.value.trim();
});
}
<input>
Handling👉 하나 이상의 <input />
을 하나의 리스너로 컨트롤 할 수 있다. 여러 개의 컨트롤을 제어하기 위해서는 name 속성을 설정해야 한다.
✍ Exmple
class MultiControlInputs extends Component {
state = {
// 사용자 등록 정보 객체 (이메일, 패스워드)
register: {
email: '',
password: ''
};
}
// 멀티 <input /> 핸들링 핸들러
handleChange = (e) => {
// 이벤트 타겟 객체로부터 name, value 속성 구조 분해 할당
const {name, value} = e.target;
// Object.assign() 메서드를 사용해 객체 합성
// register 객체 = 기존 register 객체에 사용자가 입력한 객체 합성
const register = Object.assign({}, this.state.register, { [name]: value });
// register 상태 업데이트
this.setState({ register });
}
render() {
const {register} = this.state;
return (
// Fragment
<from>
<input
type="email"
name="email"
aria-label="계정 이메일"
value={register.email}
onChange={this.handleChange} />
<input
type="password"
name="password"
aria-label="계정 패스워드"
value={register.password}
onChange={this.handleChange} />
</form>
)
}
}
<textarea>
Control👉 HTML <textarea>
요소는 사용자가 입력한 내용을 자식 텍스트 콘텐츠로 받는다.
✍ Exmple(HTML Textarea)
<textarea> 내용을 입력.</textarea>
👉React는 value
속성을 대신 사용한다. 즉, 한 줄 입력을 사용하는 폼 컨트롤과 비슷하게 작성한다.
✍ Exmple(React Textarea)
<textarea
value={this.state.value}
onChange={this.handleChange}
/>
<select>
Control👉 HTML <select>
요소는 드롭 다운 메뉴를 화면에 렌더링 한다.
✍ Exmple (HTML Select)
<select>
<option value="react">React</option>
<option value="redux">Redux</option>
<option selected value="reactRouter">React Router</option>
</select>
👉 HTML 드롭 다운 메뉴는 초기 활성화 값을 selected
속성을 사용해 처리하지만, React는 value
속성을 대신 사용한다.
✍ Exmple (React Select)
<select
value={this.state.value}
onChange={this.handleChange}
>
<option value="react">React</option>
<option value="redux">Redux</option>
<option value="reactRouter">React Router</option>
</select>
<select>
Meun👉 React 컨트롤 컴포넌트 구성된 <select>
요소는 사용자에 의해 복수의 아이템을 선택 받을 경우 두 가지가 요구 된다.
multiple
속성 값이 truevalue
값은 Array✍ Exmple
<select multiple={true} value={this.state.value} onChange={this.handleChange}>
👉 value
값을 배열로 업데이트 받아야 하기 때문에 초기 값을 배열로 설정한 후, 핸들러 내부에서는 사용자의 멀티 선택을 배열 데이터로 만드는 공정을 거쳐 새로운 배열을 할당하여 업데이트 한다.
✍ Exmple
state = {
value: []
};
handleChange(e) {
// select > option 요소 수집 후 배열 데이터로 변경
const options = Array.from(e.target.children);
// 사용자가 선택한 option 필터링
const selectedOptions = options.filter(option => option.selected);
// 필터링 된 option.value 값을 아이템으로 하는 새로운 배열 반환
const selectedOptionsValue = selectedOptions.map(option => option.value);
// 상태 업데이트
this.setState({value: selectedOptionsValue});
}
👉 컨트롤 할 수 없는 컴포넌트는 form 요소가 React 외부에서 작동하는 것처럼 작동한다. 사용자가 form 필드(input box, dropdown 등)에 데이터를 입력하면 업데이트 된 정보가 React에서 별도 처리할 필요 없이 요소에 된다. 그러나, 이는 특정 필드가 특정 값을 갖도록 강제할 수 없다는 의미이다. 특별한 경우를 제외하고는 컨트롤 컴포넌트를 사용하는 것이 좋다.
👉 HTML에서 <input type="file" />
요소는 사용자가 하나 이상의 파일을 자신의 로컬 컴퓨터에서 서버로 업로드 한다.
✍ Exmple
<input type="file" />
👉 이 컴포넌트는 프로그래밍적으로 값을 설정 할 수 없고, 사용자만이 값을 설정할 수 있기 때문에 컨트롤 할 수 없는 컴포넌트(Uncontrolled Component) 이다. 컨트롤 할 수 없는 컴포넌트의 경우 DOM 자체에서 폼 데이터를 다루게 된다. (File API 사용) 모든 state
업데이트에 대한 이벤트 핸들러를 작성하는 대신 제어할 수 없는 컴포넌트를 만들려면 ref 속성을 사용해 DOM에서 폼 값을 가져올 수 있다.
👉 ref 속성은 render()
메서드에 생성된 DOM 노드나 React 요소에 접근하는 방법이다. 핸들러에서 파일에 접근하기 위해서 DOM 노드의 Ref(참조)를 만드는 방법.
📌 ref 속성은 실제 DOM 노드 또는 React 요소에 접근해 컨트롤 하는 방법으로 React.createRef()
메서드를 사용해 DOM 요소를 참조해야 한다.
✍ Exmple
class FileInput extends Component {
constructor(props) {
super(props);
// Ref를 사용해 DOM 요소 참조
this.fileInput = React.createRef();
}
handleSubmit = (event) => {
event.preventDefault();
console.log(`선택된 파일: ${this.fileInput.current.files[0].name}`)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
업로드:
<input type="file" ref={this.fileInput} />
</label>
<br />
<button type="submit">전송</button>
</form>
);
}
}
👉 참조(Ref)는 React.createRef()를 통해 생성하고 ref 속성을 통해 DOM 노드 또는 React 요소에 참조 설정한다. 일반적으로 컴포넌트의 인스턴스가 생성(construct)될 때 참조를 인스턴스의 속성으로 추가한다.
✍ Exmple
class RefExample extends Component {
construtor(props) {
super(props);
// React.createRef()를 통해 Ref 생성 후,
// 컴포넌트 인스턴스 속성에 참조
this.refEl = createRef();
}
render() {
return (
<div className="ref-ex">
{/* ref 속성 값으로 인스턴스 속성을 연결하여 DOM 요소 참조 */}
<span ref={this.refEl}>Ref 요소 참조</span>
</div>
)
}
}
👉 render()
메서드 안에서 ref 속성이 설정된 요소 참조는 ref.current
속성을 통해 접근할 수 있다.
📌 함수형 컴포넌트는 인스턴스가 없기 때문에 함수형 컴포넌트에 ref 사용하면 오류가 출력된다.
(Warning: Function components cannot be given refs. Attempts to access this ref will fail.)
✍ Exmple
accessRef = () => {
const span = this.refEl.current
span.style.fontSize = '62px'
}
👉 React v16.8 부터는 useRef() 훅(Hook)을 사용해 함수형 컴포넌트에서도 ref 속성을 사용할 수 있다.
✍ Exmple
import React, {useRef} from 'react';
const FunctionalComponent = (props) => {
const domElRef = useRef(null);
return (
<div ref={domElRef}> ... </div>
);
}