ํผ ์ปดํฌ๋ํธ์์ ๊ธฐ๋ณธ๊ฐ(default value)์ด๋ ์ด๊ธฐ๊ฐ(initial value)์ ์ค์ ํ์ง ์์ ์ํ์์ ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ๋ฅผ ๋งํ๋ค.
๋ด๋ถ์ ์ผ๋ก ref๋ฅผ ์ฌ์ฉํด DOM ์์ฒด์์ ํผ ๋ฐ์ดํฐ๊ฐ ๋ค๋ฃจ์ด ์ง๋ฉฐ, ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ state์ ์
๋ฐ์ดํธ์ ๋ํด ๋ฆฌ๋ ๋๋ง ๋์ง ์์ ์ฑ๋ฅ์์ ์ด์ ์ด ์๋ค.
๊ทธ๋ผ Uncontrolled component
๊ฐ ๋ ์ข์๊ฑฐ ์๋์ผ? -> ์ผ๋ถ ์ํฉ์์ ์ ์ฉํ์ง๋ง, ๋ชจ๋ ์ํฉ์์ ์ฌ์ฉํ๊ธฐ์๋ ์ ํฉํ์ง ์์ ์ ์๋ค.
1. ์ธ๋ถ์์์ ์ ์ด
Uncontrolled component
์ ๊ฒฝ์ฐ, ์ผ๋ถ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ์ธ๋ถ์์ ์ ์ดํ๊ธฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์, ์ปดํฌ๋ํธ์ ๊ด๋ จ๋ ๋ก์ง์ด ๋ ๋ณต์กํด์ง ์ ์๋ค.
import React, { useRef } from "react";
function UncontrolledInput() {
const inputRef = useRef();
const handleSubmit = (event) => {
event.preventDefault();
const inputValue = inputRef.current.value;
// ์
๋ ฅ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ก์ง
};
return (
<form onSubmit={handleSubmit}>
<label>
Input:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
export default UncontrolledInput;
import React from "react";
function ControlledInput({ value, onChange, onSubmit }) {
const handleSubmit = (event) => {
event.preventDefault();
onSubmit();
};
return (
<form onSubmit={handleSubmit}>
<label>
Input:
<input type="text" value={value} onChange={onChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
export default ControlledInput;
Controlled component
์ปดํฌ๋ํธ์์๋ value
์ onChange
prop์ ํตํด ์ธ๋ถ์์ ๊ฐ์ ์ ์ดํ๋ค.
์ธ๋ถ์์ ์ด ์ปดํฌ๋ํธ์ ์
๋ ฅ๋ ๊ฐ์ ๊ฐ์ ธ์ค๊ฑฐ๋ ๊ฐ์ ์ค์ ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ฉฐ, ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ ์ดํ๊ณ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค๋ ๊ฒ.
Controlled component
๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ์ ๊ด๋ จ๋ ๋ก์ง์ด ๋ณต์กํด์ง๋๋ผ๋, ์ธ๋ถ์์ ๊ฐ์ ์ ์ดํ๋ ๊ฒ์ด ๊ฐ๋ฅํด์ ธ์ ์ปดํฌ๋ํธ๋ฅผ ๋ณด๋ค ๋ ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
2. ์ ํจ์ฑ ๊ฒ์ฌ
Controlled component
์ ๊ฒฝ์ฐ, ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ ์ด๋ฅผ ์ฌ์ฉํด ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ํํ ์ ์๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๊ฐ์ด ์ ํจํ์ง๋ฅผ ์ค์๊ฐ์ผ๋ก ๊ฒ์ฌํ ์ ์๊ณ , ํ์ํ ๊ฒฝ์ฐ์ ์ฆ์ ์๋ฌ๋ฅผ ํ์
ํ ์ ์๋ค.
๋ฐ๋ฉด Uncontrolled component
์ ๊ฒฝ์ฐ, DOM์์ ์ง์ ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์ ์ ํจ์ฑ ๊ฒ์ฌ ๊ฒฐ๊ณผ๋ฅผ ํ์ํ๊ธฐ ์ด๋ ต๋ค. ํผ์ ์ ์ถํ๊ธฐ์ํ ์ด๋ฒคํธ ํจ์์์ ๊ฒ์ฌ๊ฐ ์งํ๋๊ธฐ ๋๋ฌธ์ ์ค์๊ฐ ๊ฒ์ฌ๊ฐ ์ด๋ ต๋ค.
๋ฐ๋ผ์, Controlled component
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณด๋ค ์ง๊ด์ ์ด๊ณ ์ค์๊ฐ์ผ๋ก ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ํํ ์ ์๋ ๊ฒ.
// ์ํ๋ฅผ ์ด์ฉํด ๋ฐ๋ก ๋ฐ๋ก ๋ฆฌ๋ ๋๋ง๋๋ฉฐ, ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ๋ค.
import React, { useState } from "react";
function ControlledForm() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [nameError, setNameError] = useState("");
const [emailError, setEmailError] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
if (!name) {
setNameError("Name is required");
return;
}
if (!email) {
setEmailError("Email is required");
return;
}
// ์
๋ ฅ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ก์ง
};
const handleNameChange = (event) => {
setName(event.target.value);
setNameError("");
};
const handleEmailChange = (event) => {
setEmail(event.target.value);
setEmailError("");
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={name} onChange={handleNameChange} />
{nameError && <span>{nameError}</span>}
</label>
<label>
Email:
<input type="email" value={email} onChange={handleEmailChange} />
{emailError && <span>{emailError}</span>}
</label>
<button type="submit">Submit</button>
</form>
);
}
export default ControlledForm;
import React, { useRef } from "react";
function UncontrolledForm() {
const nameInputRef = useRef();
const emailInputRef = useRef();
const nameErrorRef = useRef();
const emailErrorRef = useRef();
const handleSubmit = (event) => {
event.preventDefault();
const nameValue = nameInputRef.current.value;
const emailValue = emailInputRef.current.value;
if (!nameValue) {
nameErrorRef.current.innerText = "Name is required";
return;
}
if (!emailValue) {
emailErrorRef.current.innerText = "Email is required";
return;
}
// ์
๋ ฅ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ก์ง
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={nameInputRef} />
<span ref={nameErrorRef}></span>
</label>
<label>
Email:
<input type="email" ref={emailInputRef} />
<span ref={emailErrorRef}></span>
</label>
<button type="submit">Submit</button>
</form>
);
}
export default UncontrolledForm;
Controlled component
๋ React์ ์ฅ์ ์ค ํ๋์ธ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ์ ํ์ฉํ ์ ์๋ค. ์ํ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์๋์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ค์ ๋ ๋๋งํ์ฌ ๋ณ๊ฒฝ๋ ์ํ๋ฅผ ๋ฐ์ํ๋์ ์ ํ์ฉํ์ฌ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ์ ์ดํ๋ฉด, ์ ํ๋ฆฌ์ผ์ด์
์ ์ํ๋ฅผ ๋์ฑ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋ง๋ค ์ ์๋ค.
import React, { useState } from "react";
function ControlledCounter() {
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1);
};
const handleDecrement = () => {
setCount(count - 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>+</button>
<button onClick={handleDecrement}>-</button>
</div>
);
}
export default ControlledCounter;
import React, { useRef } from "react";
function UncontrolledCounter() {
const countRef = useRef(0);
const handleIncrement = () => {
countRef.current += 1;
console.log("Count:", countRef.current);
};
const handleDecrement = () => {
countRef.current -= 1;
console.log("Count:", countRef.current);
};
return (
<div>
<p>Count: {countRef.current}</p>
<button onClick={handleIncrement}>+</button>
<button onClick={handleDecrement}>-</button>
</div>
);
}
export default UncontrolledCounter;
countRef๋
์ปดํฌ๋ํธ ๋ด๋ถ์์ ์ํ๋ฅผ ๊ด๋ฆฌํ์ง ์๊ณ , ๊ฐ์ ์ง์ ์
๋ฐ์ดํธํ๋ค.
handleIncrement์
handleDecrement
ํจ์์์๋ countRef.current
๋ฅผ ์ง์ ์์ ํ์ฌ ๊ฐ์ ์
๋ฐ์ดํธํ๋ค.
๊ฐ์ ์ง์ ๋ณ๊ฒฝํ์ง๋ง ๋ณ๊ฒฝ์ ๋ฐ๋ฅธ ๋ ๋๋ง ์ฒ๋ฆฌ๊ฐ ์๋์ผ๋ก ์ด๋ค์ง์ง ์๋๋ค. ์ํ๊ฐ ์์ธก ๊ฐ๋ฅํ์ง ์๋ค๊ณ ํ ์ ์๋ค. ์๋์ผ๋ก ์ฒ๋ฆฌํด ์ค ์๋ ์๋ค. -> ๋ณต์กํ๋ฐ ๊ตณ์ด;
๋ฐ๋ผ์, Controlled component
์ Uncontrolled component
๋ ์ํฉ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์ ํ๋์ด์ผ ํ๋ค.
Controlled component
๋ ์
๋ ฅ ๊ฐ์ ๊ฒ์ฆ์ด๋ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์ํธ์์ฉ์ด ํ์ํ ๊ฒฝ์ฐ์ ์ ํฉํ๋ฉฐ, Uncontrolled component
๋ ๋จ์ํ ํผ์ ๊ฒฝ์ฐ๋, ์ฑ๋ฅ ๊ฐ์ ์ด ํ์ํ ๊ฒฝ์ฐ์ ์ ํฉํ๋ค.