• ABOUT
  • PORTFOLIO
  • POSTS
  • GUESTBOOK

ยฉ 2025 BlueCool12 All rights reserved.

2025.08.31React

๐ŸŽฎ Controlled์™€ Uncontrolled - ๋ฆฌ์•กํŠธ ํผ ์ปดํฌ๋„ŒํŠธ ์ดํ•ดํ•˜๊ธฐ

๋ฆฌ์•กํŠธ๋Š” ํผ(Form) ์š”์†Œ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์— ๋”ฐ๋ผ ์ œ์–ด ์ปดํฌ๋„ŒํŠธ์™€ ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค.


1. ์ œ์–ด ์ปดํฌ๋„ŒํŠธ (Controlled Component)

ํผ ์š”์†Œ์˜ ๊ฐ’์„ ๋ฆฌ์•กํŠธ์˜ state๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

state๊ฐ€ ๋‹จ์ผ ๋ฐ์ดํ„ฐ ์ถœ์ฒ˜๊ฐ€ ๋˜๋ฉฐ ํผ ์ž…๋ ฅ ์š”์†Œ์˜ value ์†์„ฑ์€ state์— ์˜ํ•ด ๊ฒฐ์ •๋œ๋‹ค. ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์ด ๋ฐœ์ƒํ•˜๋ฉด onChange ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด state๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

import { useState } from 'react';

export default function Controlled() {
const [name, setName] = useState('');

return (
<label>
์ด๋ฆ„
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
);
}

์‚ฌ์šฉ์ž๊ฐ€ input์— ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด onChange ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  setName(e.target.value)๋ฅผ ํ†ตํ•ด state๊ฐ€ ์—…๋ฐ์ดํŠธ๋œ๋‹ค. ์ดํ›„ state ๋ณ€๊ฒฝ์— ๋”ฐ๋ฅธ ์ปดํฌ๋„ŒํŠธ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜๋ฉฐ input์˜ value๊ฐ€ ์ƒˆ๋กœ์šด state ๊ฐ’์œผ๋กœ ๊ฐฑ์‹ ๋˜๋Š” ๋ฐฉ์‹์ด๋‹ค.


- ์ œ์–ด ์ปดํฌ๋„ŒํŠธ ํ™œ์šฉ

1) ์‹ค์‹œ๊ฐ„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

if(name.length < 2) {
// ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
}


2) ์ž…๋ ฅ๊ฐ’ ๊ธฐ๋ฐ˜ UI ๋ณ€๊ฒฝ

{/* ์ž…๋ ฅ๊ฐ’์ด ์—†์œผ๋ฉด ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™” */}
<button disabled={!name}>์ œ์ถœ</button>


3) ์ž…๋ ฅ ํ˜•์‹ ๊ฐ•์ œ

<input
type="text"
value={name}
onChange={(e) =>
setName(
// ์ˆซ์ž๋งŒ ์ž…๋ ฅ ํ—ˆ์šฉ
e.target.value.replace(/[^0-9]/g, '')
)
}โ€‹
/>


2. ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ(Uncontrolled Component) 

ํผ ๋ฐ์ดํ„ฐ๋ฅผ DOM์ด ์ง์ ‘ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

์ฆ‰ ์ž…๋ ฅ๊ฐ’์„ state๋กœ ๋งค๋ฒˆ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ  ํ•„์š”ํ•  ๋•Œ๋งŒ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์ด๋‹ค. ๋ฆฌ์•กํŠธ์—์„œ๋Š” ๋ณดํ†ต ref๋ฅผ ์‚ฌ์šฉํ•ด DOM ์š”์†Œ์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ๊ฐ’์„ ์ฝ๋Š”๋‹ค.

import { useRef } from 'react';

export default function Uncontrolled() {
const inputRef = useRef(null);

function handleSubmit(e) {
e.preventDefault();
const value = inputRef.current?.value ?? '';
alert('์ž…๋ ฅ๊ฐ’: ' + value);
}

return (
<form onSubmit={handleSubmit}>
<label>
์ด๋ฆ„
<input
type="text"
defaultValue="BlueCool"
ref={inputRef}
/>
</label>
<button type="submit">๋“ฑ๋ก</button>
</form>
);
}

ํผ ๋ฐ์ดํ„ฐ์˜ ์ถœ์ฒ˜๊ฐ€ state๊ฐ€ ์•„๋‹Œ DOM์ด ๋˜๋ฉฐ value ๋Œ€์‹  defaultValue๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ํ•„์š”ํ• ๋•Œ๋งŒ ref๋ฅผ ํ†ตํ•ด input ์š”์†Œ์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค. ์ž…๋ ฅ ์‹œ state ๋ณ€๊ฒฝ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.


- ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ ํ™œ์šฉ

1) ํŒŒ์ผ ์ž…๋ ฅ
๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ œ์–ด ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ์ด ๊ถŒ์žฅ๋˜์ง€๋งŒ ํŒŒ์ผ ์ž…๋ ฅ์˜ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ € ๋ณด์•ˆ ์ •์ฑ… ๋•Œ๋ฌธ์— value๋ฅผ ์ง์ ‘ ์ œ์–ดํ•  ์ˆ˜ ์—†๋‹ค.

import { useRef } from 'react';

function FileInput() {
const ref = useRef(null);

return (
<div>
<input type="file" ref={ref} />
<button
onClick={() => {
if (ref.current) ref.current.value = '';
}}
>
์ดˆ๊ธฐํ™”
</button>
</div>
);
}
์ด์ „ ๊ธ€
๐Ÿž JPA N+1 ๋ฌธ์ œ - Fetch Join & EntityGraph
๋‹ค์Œ ๊ธ€
๐Ÿค ์ฝ๊ธฐ ์ข‹์€ ์ฝ”๋“œ๋ฅผ ์œ„ํ•œ ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜ ๊ฐ€์ด๋“œ
์žฅ์‹์šฉ ๋กœ๊ณ