Reacting to Input with State

date
2026-01-30
order
1
link
  • Reacting to Input with State โ€“ React

You will learn

  • ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹๊ณผ ๋ช…๋ นํ˜• ๋ฐฉ์‹์˜ ์ฐจ์ด
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ€์ ธ์•ผ ํ•  ์‹œ๊ฐ์  state๋“ค์„ ๋‚˜์—ดํ•˜๋Š” ๋ฒ•
  • ํ•œ ์‹œ๊ฐ์  state์—์„œ ๋‹ค๋ฅธ ์‹œ๊ฐ์  state๋กœ ๋„˜์–ด๊ฐ€๋Š” ๋ฐฉ๋ฒ•

์„ ์–ธํ˜• UI

UI๋ฅผ ์ƒ๊ฐํ•  ๋•Œ ์šฐ๋ฆฌ๋“ค์€ ๋ณดํ†ต ์‚ฌ์šฉ์ž๋“ค์˜ ํ–‰๋™์— ๋งž์ถฐ ๋ณ€ํ™”ํ•˜๋Š”๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•œ๋‹ค. ๊ฐ€๋ น ์‚ฌ์šฉ์ž๊ฐ€ ํผ์„ ์ œ์ถœํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž :

  • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ์ฐฝ์— ๊ธ€์ž๋ฅผ ์ ์–ด์•ผ ์ „์†ก ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ๋œ๋‹ค.
  • ์ „์†ก ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋กœ๋”ฉ์„ ์•Œ๋ฆฌ๋Š” ์Šคํ”ผ๋„ˆ์™€ ํ•จ๊ป˜ ์ž ์‹œ ๋น„ํ™œ์„ฑํ™” ๋œ๋‹ค.
  • ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๋ฉด ํผ์ด ์‚ฌ๋ผ์ง€๊ณ , ์ œ์ถœ ์™„๋ฃŒ๋ฅผ ์•Œ๋ฆฌ๋Š” ์•ˆ๋‚ด๋ฌธ๊ตฌ๊ฐ€ ๋‚˜ํƒ€๋‚œ๋‹ค.
  • ์š”์ฒญ ์ฒ˜๋ฆฌ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ์—๋Ÿฌ ์•Œ๋ฆผ์ด ๋‚˜ํƒ€๋‚œ๋‹ค.

๋ฆฌ์•กํŠธ ์ด์ „์˜ ๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ฒด๊ณ„์—์„œ, ์œ„์˜ ์‚ฌํ•ญ๋“ค์€ ๋ชจ๋‘ ๊ฐœ๋ฐœ์ž์— ์˜ํ•ด ๊ตฌํ˜„๋˜์–ด์•ผ ํ•  ์‚ฌํ•ญ์ด๋‹ค. ์ฆ‰ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ผ์ผ์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์–ด์•ผ ํ–ˆ๋‹ค๋Š” ๋ง์ด๋‹ค. ๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๋งˆ์น˜ ํƒ์‹œ์— ํƒ€์„œ ํƒ์‹œ ๊ธฐ์‚ฌ์—๊ฒŒ ๋ชฉ์ ์ง€๋ฅผ ๋งํ•ด์ฃผ๋Š” ๋Œ€์‹  ๊ทธ๋•Œ๋งˆ๋‹ค ์šฐํšŒ์ „์ธ์ง€ ์ขŒํšŒ์ „์ธ์ง€ ์ง์ง„ํ•ด์•ผํ•˜๋Š”์ง€๋ฅผ ๋งํ•ด์ฃผ๋Š”๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

์œ„์˜ ํผ ์ œ์ถœ ์ƒํ™ฉ์„ ๋ช…๋ นํ˜• ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

async function handleFormSubmit(e) {
  e.preventDefault();
  disable(textarea);
  disable(button);
  show(loadingMessage);
  hide(errorMessage);
  try {
    await submitForm(textarea.value);
    show(successMessage);
    hide(form);
  } catch (err) {
    show(errorMessage);
    errorMessage.textContent = err.message;
  } finally {
    hide(loadingMessage);
    enable(textarea);
    enable(button);
  }
}

function handleTextareaChange() {
  if (textarea.value.length === 0) {
    disable(button);
  } else {
    enable(button);
  }
}

function hide(el) {
  el.style.display = 'none';
}

function show(el) {
  el.style.display = '';
}

function enable(el) {
  el.disabled = false;
}

function disable(el) {
  el.disabled = true;
}

function submitForm(answer) {
  // Pretend it's hitting the network.
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (answer.toLowerCase() === 'istanbul') {
        resolve();
      } else {
        reject(new Error('Good guess but a wrong answer. Try again!'));
      }
    }, 1500);
  });
}

let form = document.getElementById('form');
let textarea = document.getElementById('textarea');
let button = document.getElementById('button');
let loadingMessage = document.getElementById('loading');
let errorMessage = document.getElementById('error');
let successMessage = document.getElementById('success');
form.onsubmit = handleFormSubmit;
textarea.oninput = handleTextareaChange;

๊ฐ„๋‹จํ•œ ํผ ์ œ์ถœ UI๋งŒ ํ•ด๋„ ์ฝ”๋“œ๊ฐ€ ์ด๋ ‡๊ฒŒ ๊ธธ์–ด์ง€๋Š”๋ฐ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ทœ๋ชจ๊ฐ€ ๊ฑฐ๋Œ€ํ•ด์ง€๋ฉด ๊ทธ ์ฝ”๋“œ์˜ ๋ณต์žก๋„๋Š” ์–ผ๋งˆ๋งŒํ• ๊นŒ?

๋ฆฌ์•กํŠธ๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์ค€๋‹ค. ์„ ์–ธํ˜• UI๋Š” ๊ฐ UI๊ฐ€ ์–ด๋•Œ์•ผ ํ•˜๋Š”์ง€๋ฅผ ์ •ํ•˜๋ฉด ๋ฆฌ์•กํŠธ๊ฐ€ ๊ฐ ํ™”๋ฉด์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ• ๊ฒƒ์ธ์ง€ ์Šค์Šค๋กœ ํ•ด๊ฒฐํ•œ๋‹ค. ํƒ์‹œ์— ํƒ€์„œ ๋ชฉ์ ์ง€๋งŒ ๋งํ•˜๋ฉด ๋˜๋Š”๊ฒƒ์ฒ˜๋Ÿผ.

์„ ์–ธํ˜• ๋ฐฉ์‹์œผ๋กœ UI ์ž‘์„ฑํ•˜๊ธฐ

  1. Identify : ์ปดํฌ๋„ŒํŠธ์˜ ๊ฐ ์‹œ๊ฐ์  ์ƒํƒœ๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.
  2. Determine : ์ƒํƒœ์˜ ๋ณ€ํ™”๋ฅผ ์ผ์œผํ‚ฌ ๊ฒƒ์ด ๋ฌด์–ธ์ธ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.
  3. Represent : useState๋กœ ๋ฉ”๋ชจ๋ฆฌ์˜ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค.
  4. Remove : ํ•„์š” ์—†๋Š” ์ƒํƒœ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
  5. Connect : ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค.

1. Identify : ์ปดํฌ๋„ŒํŠธ์˜ ๊ฐ ์‹œ๊ฐ์  ์ƒํƒœ๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.

UI ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋–ค ๋ชจ์Šต์„ ๊ฐ€์งˆ๊ฒƒ์ธ์ง€ ๋จผ์ € ์ƒ๊ฐํ•ด์•ผ ํ•œ๋‹ค. ๊ฐ€๋ น ํผ ์ œ์ถœ์— ์žˆ์–ด์„œ๋Š” ๋‹ค์Œ์˜ ์ƒํƒœ๋“ค์ด ์žˆ์„๊ฒƒ์ด๋‹ค :

  • empty - ์ œ์ถœ ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”
  • typing - ์ œ์ถœ ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
  • submitting - ์ž…๋ ฅ๊ณผ ์ œ์ถœ ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”
  • success - ์ „์ฒด ํผ์ด ์‚ฌ๋ผ์ง€๊ณ  ์•ˆ๋‚ด ๋ฌธ๊ตฌ ์ถœ๋ ฅ
  • error - typing์ƒํƒœ์™€ ๊ฐ™์ง€๋งŒ ์—๋Ÿฌ ๋ฌธ๊ตฌ๋„ ํ•จ๊ป˜ ์ถœ๋ ฅ

2. Determine : ์ƒํƒœ์˜ ๋ณ€ํ™”๋ฅผ ์ผ์œผํ‚ฌ ๊ฒƒ์ด ๋ฌด์–ธ์ธ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.

state๋ฅผ ๋ณ€ํ™”์‹œํ‚ค๋Š” ํŠธ๋ฆฌ๊ฑฐ๋Š” ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค :

  • ์‚ฌ์šฉ์ž ์ž…๋ ฅ - ๋งˆ์šฐ์Šค ํด๋ฆญ, ํ‚ค๋ณด๋“œ ์ž…๋ ฅ, ๋งํฌ ์ด๋™ ๋“ฑ
  • ์ปดํ“จํ„ฐ ์ž…๋ ฅ - ๋„คํŠธ์›Œํฌ ์‘๋‹ต ๋„์ฐฉ, ํƒ€์ž„์•„์›ƒ, ์ด๋ฏธ์ง€ ๋กœ๋”ฉ ๋“ฑ

์ด์ œ ๊ฐ ์ž…๋ ฅ๋“ค์ด ์–ด๋–ป๊ฒŒ ์ƒํƒœ๋ฅผ ๋ณ€ํ™”ํ•˜๋Š”์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.

  • ์ž…๋ ฅ์ฐฝ์ด ๋น„์–ด์žˆ๋‹ค๋ฉด empty ์ƒํƒœ, ๋น„์–ด์žˆ์ง€ ์•Š๋‹ค๋ฉด typing ์ƒํƒœ์ผ ๊ฒƒ์ด๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์ถœ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด submitting ์ƒํƒœ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.
  • ์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์—ˆ๋‹ค๋Š” ๋„คํŠธ์›Œํฌ ์‘๋‹ต์ด ๋„์ฐฉํ•˜๋ฉด success์ƒํƒœ๋กœ, ๋ฐ˜๋Œ€๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด error ์ƒํƒœ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

3. Represent : useState๋กœ ๋ฉ”๋ชจ๋ฆฌ์˜ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค.

๋‹ค์Œ์œผ๋กœ ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ์‹œ๊ฐ์  state๋ฅผ useState๋กœ ํ‘œํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);

const [isEmpty, setIsEmpty] = useState(true);
const [isTyping, setIsTyping] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);

4. Remove : ํ•„์š” ์—†๋Š” ์ƒํƒœ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.

์œ„์— ์ž‘์„ฑํ•œ state๋“ค์„ ๊ฒ€ํ† ํ•ด๋ณด์ž. ๋‹ค์Œ์˜ ์งˆ๋ฌธ๋“ค์„ ํ†ตํ•ด์„œ :

  • state๊ฐ€ ์—ญ์„ค์„ ์ผ์œผํ‚ค๋Š”๊ฐ€? - ๊ฐ€๋ น isTyping๊ณผ isSubmitting์ด ๋™์‹œ์— true์ผ ์ˆ˜๋Š” ์—†๋‹ค. ์ด๋Ÿฌํ•œ ์—ญ์„ค์€ ๋ณดํ†ต state๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ œํ•œ๋˜์ง€ ์•Š์•˜์Œ์„ ์˜๋ฏธํ•œ๋‹ค. ์ด ๋‘ state๋Š” ๋„ค ๊ฐ€์ง€ ์กฐํ•ฉ์„ ๊ฐ€์ง€์ง€๋งŒ(์ฐธ-์ฐธ, ์ฐธ-๊ฑฐ์ง“, ๊ฑฐ์ง“-์ฐธ, ๊ฑฐ์ง“-๊ฑฐ์ง“) ์œ ํšจํ•œ ๊ฒƒ์€ ์„ธ ๊ฐœ ๋ฟ์ด๋‹ค(๋‘˜ ๋‹ค ์ฐธ์ธ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•ด์„œ). ์ด๋Ÿฐ ๊ฒฝ์šฐ ์ด state๋“ค์„ ํ•ฉ์ณ์„œ ์„ธ ๊ฐ’(isTyping, isSubmitting, success)์„ ๊ฐ€์ง€๋Š” ํ•˜๋‚˜์˜ state๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ™์€ ์ •๋ณด๊ฐ€ ์ด๋ฏธ ๋‹ค๋ฅธ state์— ์žˆ๋Š”๊ฐ€? - ์œ„์™€ ๋น„์Šทํ•œ ๊ฒฝ์šฐ๋กœ, isEmpty์™€ isTyping์€ ๋™์‹œ์— ์ฐธ์ผ ์ˆ˜ ์—†๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์— ๋‘ state๋ฅผ ๋ณ„๋„๋กœ ๋ถ„๋ฆฌํ•˜๋ฉด ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ์— isEmpty๋Š” answer.length===0๊ณผ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— isEmpty state๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹ค๋ฅธ state๋ฅผ ๋ฐ”๊ฟ”์„œ ๋˜‘๊ฐ™์€ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋Š”๊ฐ€? - isError ๋ผ๋Š” state๋Š” error !=== null๊ณผ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— isError ๋Œ€์‹  error ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ด ๋ฆฌํŒฉํ† ๋ง์˜ ๊ฒฐ๊ณผ๋กœ state๋Š” ์ด๋ ‡๊ฒŒ ์ •๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค.

const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success'

์š”์•ฝ :

  • isEmpty์‚ญ์ œ.
  • isTyping,isSubmitting,success๋ฅผ ํ•˜๋‚˜์˜ ์ƒํƒœ๋กœ ํ•ฉ์ณค๋‹ค.
  • isError ์‚ญ์ œ.

5. Connect : ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค.

์ด์ œ state๋“ค์„ ์ •๋ฆฌํ–ˆ์œผ๋‹ˆ ์ด state๋“ค์„ ์„ค์ •ํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์—ฐ๊ฒฐํ•ด์•ผ ํ•œ๋‹ค.

export default function Form() {
  const [answer, setAnswer] = useState('');
  const [error, setError] = useState(null);
  const [status, setStatus] = useState('typing');

  if (status === 'success') {
    return <h1>That's right!</h1>
  }

  async function handleSubmit(e) {
    e.preventDefault();
    setStatus('submitting');
    try {
      await submitForm(answer);
      setStatus('success');
    } catch (err) {
      setStatus('typing');
      setError(err);
    }
  }

  function handleTextareaChange(e) {
    setAnswer(e.target.value);
  }

  return (
    <>
      <h2>City quiz</h2>
      //...
      <form onSubmit={handleSubmit}>
        <textarea
          value={answer}
          onChange={handleTextareaChange}
          disabled={status === 'submitting'}
        />
        <br />
        <button disabled={
          answer.length === 0 ||
          status === 'submitting'
        }>
          Submit
        </button>
        {error !== null &&
          <p className="Error">
            {error.message}
          </p>
        }
      </form>
    </>
  );
}

function submitForm(answer) {
  // Pretend it's hitting the network.
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let shouldError = answer.toLowerCase() !== 'lima'
      if (shouldError) {
        reject(new Error('Good guess but a wrong answer. Try again!'));
      } else {
        resolve();
      }
    }, 1500);
  });
}

์ด ์ฝ”๋“œ๋งŒ ๋ณด๋ฉด ์‚ฌ์‹ค ์œ„์˜ ๋ช…๋ นํ˜• ์ฝ”๋“œ๋ณด๋‹ค ์ฝ”๋“œ๋Ÿ‰์€ ๋งŽ์ง€๋งŒ, ํ›จ์”ฌ ๊ฐ€๋…์„ฑ์ด ์ข‹๊ณ  ๊ทธ๋Ÿฌ๊ธฐ ๋•Œ๋ฌธ์— ๋œ ์—ฐ์•ฝ(ํ—ˆ์ˆ )ํ•˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฝ”๋“œ์˜ ์ถ”๊ฐ€์™€ ๋ณ€๊ฒฝ๋„ ์šฉ์ดํ•ด์ง„๋‹ค.

์˜ˆ์‹œ ๋ฌธ์ œ

1. CSS ํด๋ž˜์Šค ํ† ๊ธ€

export default function Picture() {
  return (
    <div className="background background--active">
      <img
        className="picture" // picture--active 
        alt="Rainbow houses in Kampung Pelangi, Indonesia"
        src="https://i.imgur.com/5qwVYb1.jpeg"
      />
    </div>
  );
}

์ด๋ฏธ์ง€๋ฅผ ๋ˆ„๋ฅด๋ฉด ๋ฐฐ๊ฒฝ์ด ์‚ฌ๋ผ์ง€๊ณ (backgroud--activeํด๋ž˜์Šค๋ฅผ ์ œ๊ฑฐ) ์ด๋ฏธ์ง€์— picture--active๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ๋ฐ˜๋Œ€๋กœ ๋‹ค์‹œ ๋ฐฐ๊ฒฝ์„ ๋ˆ„๋ฅด๋ฉด background--active ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  picture--active ํด๋ž˜์Šฌ๋ฅด ์ œ๊ฑฐํ•˜๋„๋ก ์ˆ˜์ •ํ•ด์•ผํ•œ๋‹ค.

export default function Picture() {
  const [element,setElement] = useState("");
  
  return (
    <div className={`background ${element==="background" ? "background--active" : ""}`}
      onClick={()=>setElement("background")}>
      <img
        className={`picture ${element==="image" ? "picture--active":""}`}
        alt="Rainbow houses in Kampung Pelangi, Indonesia"
        src="https://i.imgur.com/5qwVYb1.jpeg"
        onClick={(e)=>{
          e.stopPropagation();
          setElement("image");}}
      />
    </div>
  );
}

๋‹ต์•ˆ๊ณผ ๋‹ค๋ฅด์ง€๋งŒ ๋‚˜๋Š” ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ–ˆ๋‹ค.

3. ๋ช…๋ นํ˜• ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง

์žฌ๋ฐŒ๊ฒŒ ๋ฆฌ์•กํŠธ๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฌธ์ œ. ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฆฌ์•กํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ํžŒํŠธ๋ฅผ ์ค€๋‹ค.

let firstName = 'Jane';
let lastName = 'Jacobs';
let isEditing = false;

function handleFormSubmit(e) {
  e.preventDefault();
  setIsEditing(!isEditing);
}

function handleFirstNameChange(e) {
  setFirstName(e.target.value);
}

function handleLastNameChange(e) {
  setLastName(e.target.value);
}

function setFirstName(value) {
  firstName = value;
  updateDOM();
}

function setLastName(value) {
  lastName = value;
  updateDOM();
}

function setIsEditing(value) {
  isEditing = value;
  updateDOM();
}

function updateDOM() {
  if (isEditing) {
    editButton.textContent = 'Save Profile';
    // TODO: show inputs, hide content
    hide(firstNameText);
    hide(lastNameText);
    show(firstNameInput);
    show(lastNameInput);
  } else {
    editButton.textContent = 'Edit Profile';
    // TODO: hide inputs, show content
    hide(firstNameInput);
    hide(lastNameInput);
    show(firstNameText);
    show(lastNameText);
  }
  // TODO: update text labels
  firstNameText.textContent = firstName;
  lastNameText.textContent = lastName;
  helloText.textContent = (
    'Hello ' +
    firstName + ' ' +
    lastName + '!'
  );
}

function hide(el) {
  el.style.display = 'none';
}

function show(el) {
  el.style.display = '';
}

let form = document.getElementById('form');
let editButton = document.getElementById('editButton');
let firstNameInput = document.getElementById('firstNameInput');
let firstNameText = document.getElementById('firstNameText');
let lastNameInput = document.getElementById('lastNameInput');
let lastNameText = document.getElementById('lastNameText');
let helloText = document.getElementById('helloText');
form.onsubmit = handleFormSubmit;
firstNameInput.oninput = handleFirstNameChange;
lastNameInput.oninput = handleLastNameChange;

editButton์„ ํด๋ฆญ -> handleFormSubmit -> setIsEditing -> <b>ํƒœ๊ทธ ์ˆจ๊ธฐ๊ณ  input ํƒœ๊ทธ ๋…ธ์ถœ -> oninput ํ•ธ๋“ค๋Ÿฌ -> ๊ธ€์ž ์ž…๋ ฅ์‹œ๋งˆ๋‹ค updateDOM ํ˜ธ์ถœ -> firstNameText.textContent = firstName ์œผ๋กœ ์•„๋ž˜์— ์ถœ๋ ฅ๋˜๋Š” ๋ฌธ๊ตฌ ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ

์ด๋Ÿฐ ํ๋ฆ„์œผ๋กœ ์‹คํ–‰๋˜๋Š”๋ฐ ์ •๋ง ๋ฆฌ์•กํŠธ ์ „์—๋Š” ์ด๊ฑธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ํ•˜๋‚˜ํ•˜๋‚˜ ์ž‘์„ฑํ–ˆ์–ด์•ผ ํ–ˆ๊ตฌ๋‚˜.. ๋†€๋ž๋‹ค.