Preserving and Resetting State

date
2026-02-05
order
4
link
  • Preserving and Resetting State โ€“ React

You will learn

  • ๋ฆฌ์•กํŠธ๊ฐ€ ์–ธ์ œ state๋ฅผ ๋ณด์กดํ•˜๊ณ  ์–ธ์ œ ์ดˆ๊ธฐํ™” ํ•˜๋Š”์ง€
  • ๋ฆฌ์•กํŠธ๊ฐ€ ๊ฐ•์ œ๋กœ ์ปดํฌ๋„ŒํŠธ์˜ state๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•
  • key๊ฐ’๊ณผ ํƒ€์ž…์ด ์–ด๋–ป๊ฒŒ state์˜ ๋ณด์กด ์—ฌ๋ถ€์— ์˜ํ–ฅ์„ ๋ผ์น˜๋Š”์ง€

state๋Š” ๋ Œ๋” ํŠธ๋ฆฌ ์•ˆ์— ์žˆ๋‹ค

๋ฆฌ์•กํŠธ๋Š” ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๋ฅผ ๋ Œ๋” ํŠธ๋ฆฌ ๋ผ๋Š” ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ ๋‹ค. ํ”ํžˆ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ state๋ฅผ ์„ ์–ธํ•˜๋‹ˆ๊นŒ state๊ฐ€ ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์œ„์น˜ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์œผ๋‚˜ (ํŽธ์˜์ƒ ๊ทธ๋ ‡๊ฒŒ ์–˜๊ธฐํ•˜๊ธฐ๋„ ํ•˜์ง€๋งŒ), ์‚ฌ์‹ค state๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹Œ ๋ฆฌ์•กํŠธ์— ์žˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ์‹ค ๋ Œ๋”๋ง ๋กœ์ง์ด๊ณ , ๋ Œ๋”๋ง์ด ์‹คํ–‰ ๋  ๋•Œ ํ•„์š”ํ•œ ์ •๋ณด๋“ค์€ ๋ฆฌ์•กํŠธ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด๋‹ค. setState ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ state ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ฆฌ์•กํŠธ๋Š” ํ•ด๋‹น state๋ฅผ ๋ Œ๋” ํŠธ๋ฆฌ ์•ˆ์—์„œ ์ฐพ์•„ ํ•ด๋‹น ์œ„์น˜์˜ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๋กœ์ง์„ ์ƒˆ๋กœ ์—…๋ฐ์ดํŠธ๋œ state๋ฅผ ์ฃผ๊ณ  ์‹คํ–‰์‹œํ‚จ๋‹ค.

๊ฐ™์€ ์ž๋ฆฌ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ์˜ state

export default function App() {
  const [isFancy, setIsFancy] = useState(false);
  return (
    <div>
      {isFancy ? (
        <Counter isFancy={true} />
      ) : (
        <Counter isFancy={false} />
      )}
      <label>
        <input
          type="checkbox"
          checked={isFancy}
          onChange={e => {
            setIsFancy(e.target.checked)
          }}
        />
        Use fancy styling
      </label>
    </div>
  );
}

function Counter({ isFancy }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);
  //...
  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
    //...

์—ฌ๊ธฐ์„œ score state์˜ ๋ณด์กด ์—ฌ๋ถ€๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.

isFancy ๋ณ€ํ™”์— ๋”ฐ๋ผ Counter ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋˜์ง€๋งŒ state๋Š” ๋ณด์กด๋˜๋Š”๋ฐ ์™œ ๊ทธ๋Ÿด๊นŒ? Counter ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด๋ฉด ๋งจ ์œ„์— div ํƒœ๊ทธ๋ฅผ ๊ฐ€์ง€๋Š”๋ฐ, ๋ฆฌ์•กํŠธ๊ฐ€ ๋ณด๋Š” ๋ Œ๋” ํŠธ๋ฆฌ ์•ˆ์—๋Š” App์ด๋ผ๋Š” ํŠธ๋ฆฌ ๋ฃจํŠธ์˜ ์ฒซ ์ž์‹์ธ div์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ฐ™์€ ์œ„์น˜ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์˜ state

export default function App() {
  const [isFancy, setIsFancy] = useState(false);
  return (
    <div>
      {isFancy ? (
        <div>
          <Counter isFancy={true} />
        </div>
      ) : (
        <section>
          <Counter isFancy={false} />
        </section>
      )}

์ด๋ ‡๊ฒŒ div์—์„œ section ์œผ๋กœ ํƒœ๊ทธ๊ฐ€ ์™„์ „ํžˆ ๋ณ€ํ•ด๋ฒ„๋ฆฌ๋ฉด ๊ฐ™์€ ์œ„์น˜๋ผ๊ณ  ํ•˜๋”๋ผ๋„ score state๋Š” ์ดˆ๊ธฐํ™”๋˜์–ด 0์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค.

[!faq] ํƒ€์ž…์ด๋ž€? div ํƒœ๊ทธ๋ฅผ ๊ฐ€์ง€๋Š” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ผ๋ฉด? ๋งŒ์•ฝ ๋™๋ช…์˜ score๋ผ๋Š” state๋ฅผ ๊ฐ€์ง€๊ณ  ๋งจ ์œ„๊ฐ€ div ํƒœ๊ทธ๋กœ ์ด๋ฃจ์–ด์ง„ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•ด๋‹น ์œ„์น˜์— Counter๋Œ€์‹  ๋ Œ๋”๋ง ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๊ฐ™์€ ์œ„์น˜์˜ div๋‹ˆ๊นŒ score state๊ฐ€ ์œ ์ง€๋ ๊นŒ ์•„๋‹ˆ๋ฉด ์ดˆ๊ธฐํ™” ๋ ๊นŒ?

์ดˆ๊ธฐํ™” ๋œ๋‹ค. ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์ด HTML ํƒœ๊ทธ์˜ ์ข…๋ฅ˜๋ฅผ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฌธ์„œ์—์„œ ํ•œ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•œ๋‹ค. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ ๋งˆ๋‹ค ๋ถ€๋ชจ ์•ˆ์— ์†ํ•œ ํ•จ์ˆ˜์ธ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค๋ฅธ ์ฃผ์†Œ๊ฐ’์„ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ๋˜‘๊ฐ™์€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณด์—ฌ๋„ ์ฃผ์†Œ๊ฐ’์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ํƒ€์ž…์ด๋ผ๊ณ  ๋ฆฌ์•กํŠธ๋Š” ํŒ๋‹จํ•˜๊ณ  state๋ฅผ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์•„์˜ˆ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ผ๋ฉด ์• ์ดˆ์— ๋‹ค๋ฅธ ์ฃผ์†Œ๊ฐ’์„ ๊ฐ€์ง€๊ฒŒ ๋˜๊ณ , ๋‹ค๋ฅธ ํƒ€์ž…์ด ๋œ๋‹ค.

๊ฐ™์€ ์œ„์น˜์—์„œ state ์ดˆ๊ธฐํ™” ํ•˜๊ธฐ

์–ด๋–ค ์ด์œ ๋กœ ๊ฐ™์€ ์œ„์น˜์—์„œ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ state๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค (๋ฌธ์„œ์—์„œ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์‹œ๋Š” ํ˜„์‹ค์„ฑ์ด ๋–จ์–ด์ง€๋Š”๊ฒƒ ๊ฐ™์•„ ๋”ฐ๋กœ ์ฐพ์•˜๋‹ค) :

  • ์„ค๋ฌธ์กฐ์‚ฌ์™€ ๊ฐ™์€ ๋‹ค๋‹จ๊ณ„ ํผ - 1๋ฒˆ ๋ฌธํ•ญ์— ๋‹ต์„ ํ•˜๊ณ  ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋„˜์–ด๊ฐ”์„๋•Œ 1๋ฒˆ ๋ฌธํ•ญ์— ๋Œ€ํ•œ ๋‹ต์ด ๋‚จ์•„์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๋ธ”๋กœ๊ทธ ์—๋””ํ„ฐ๋‚˜ ๋ฉ”๋ชจ์•ฑ - A๊ธ€์„ ์ˆ˜์ •ํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ๋ฆฌ์ŠคํŠธ์—์„œ ๋ฐ”๋กœ B๊ธ€ ์ˆ˜์ •์œผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค๋ฉด A๊ธ€์˜ ๋‚ด์šฉ์ด B ๊ธ€์˜ ๋ณธ๋ฌธ ์œ„์น˜์— ๊ทธ๋Œ€๋กœ ์ ์šฉ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.

์ด๋Ÿด๋•Œ ํ•  ์ˆ˜ ์žˆ๋Š” ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•์€ ์ปดํฌ๋„ŒํŠธ์— key๊ฐ’์„ ์ฃผ๋Š”๊ฒƒ์ด๋‹ค. key ๊ฐ’์€ ๋ฐฐ์—ด์„ ๋ Œ๋”๋ง ํ•  ๋•Œ๋งŒ ํ•„์š”ํ•œ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” key๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ฌด์กฐ๊ฑด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ผ๊ณ  ํŒ๋‹จํ•œ๋‹ค.

์ œ๊ฑฐ๋œ ์ปดํฌ๋„ŒํŠธ์˜ state ๋ณด์กดํ•˜๊ธฐ

์–ด๋–ค ์ด์œ ๋กœ๋Š” ๋ฐ˜๋Œ€๋กœ ์‚ฌ๋ผ์ง„ ์ปดํฌ๋„ŒํŠธ์˜ state๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ๋‹ค. ์œ„์˜ ์˜ˆ์‹œ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ด๋ณด๋ฉด, 1๋ฒˆ ๋ฌธํ•ญ์— ๋‹ต์„ ์ ๋‹ค๊ฐ€ ์ œ์ถœํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ ๋ฌธํ•ญ์œผ๋กœ ๋„˜์–ด๊ฐ”์ง€๋งŒ, ๋‹ค์‹œ ๋Œ์•„์™”์„๋•Œ ์ ์—ˆ๋˜ ๋‹ต์ด ๋‚จ์•„์žˆ๊ธฐ๋ฅผ ์›ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿด๋• ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

  • ์–ธ๋งˆ์šดํŠธ ๋Œ€์‹  CSS๋กœ ์•ˆ๋ณด์ด๊ฒŒ ๋งŒ๋“ ๋‹ค.
  • state๋ฅผ ์ƒ์œ„๋กœ ์˜ฌ๋ฆฌ๊ณ  ๊ฐ ๋ฌธํ•ญ๋ณ„ ๋‹ต์•ˆ state๋ฅผ ๋ถ€๋ชจ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ฐ€ ์ž์‹์—๊ฒŒ props๋กœ ๊ฑด๋‚ด์ค€๋‹ค.
  • ๋ฆฌ์•กํŠธ ์ด์™ธ์˜ ๋‹ค๋ฅธ ์ €์žฅ์†Œ๋ฅผ ์ด์šฉํ•œ๋‹ค : localStorage๋‚˜ ๋‹ค๋ฅธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค.

์˜ˆ์‹œ ๋ฌธ์ œ

1. ์ž…๋ ฅ๊ฐ’ ์ดˆ๊ธฐํ™” ๋ฌธ์ œ

export default function App() {
  const [showHint, setShowHint] = useState(false);
  if (showHint) {
    return (
      <div>
        <p><i>Hint: Your favorite city?</i></p>
        <Form />
        <button onClick={() => {
          setShowHint(false);
        }}>Hide hint</button>
      </div>
    );
  }
  return (
    <div>
      <Form />
      <button onClick={() => {
        setShowHint(true);
      }}>Show hint</button>
    </div>
  );
}

์œ„์˜ ์ฝ”๋“œ์—์„œ Form ์ปดํฌ๋„ŒํŠธ์˜ ์œ„์น˜๊ฐ€ ์ฒซ ๋ฒˆ์งธ์™€ ๋‘ ๋ฒˆ์งธ๋ฅผ ์˜ค๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ๋ Œ๋”๋ง๋งˆ๋‹ค state๊ฐ€ ์ดˆ๊ธฐํ™” ๋œ๋‹ค.

ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด๋ ‡๊ฒŒ ํ•ญ์ƒ ์ปดํฌ๋„ŒํŠธ์˜ ์œ„์น˜๋ฅผ ๊ณ ์ •์‹œ์ผœ์•ผ ํ•œ๋‹ค.

//...
<div>
      {showHint && // p ํƒœ๊ทธ or null
        <p><i>Hint: Your favorite city?</i></p>
      } 
      <Form />
      {showHint ? (
        <button onClick={() => {
          setShowHint(false);
        }}>Hide hint</button>
      ) : (
        <button onClick={() => {
          setShowHint(true);
        }}>Show hint</button>
      )}
</div>
//...

2. ์ž…๋ ฅ์ฐฝ ๋งž๋ฐ”๊พธ๊ธฐ

export default function App() {
//...
  if (reverse) {
    return (
      <>
        <Field key="lastName" label="Last name" /> 
        <Field key="firstName" label="First name" />
        {checkbox}
      </>
    );
  } else {
    return (
      <>
        <Field key="firstName" label="First name" /> 
        <Field key="lastName" label="Last name" />
        {checkbox}
      </>
    );    
  };
}
function Field({ label }) {
  const [text, setText] = useState('');
  return (
    <label>
      {label}:{' '}
      <input
        type="text"
        value={text}
        placeholder={label}
        onChange={e => setText(e.target.value)}
      />
    </label>
  );
}

์•ฝ๊ฐ„ ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ์ธ๋ฐ, ๋ฆฌ์•กํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง์„ ํ•  ๋•Œ ๊ฐ™์€ key๊ฐ’์„ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์œ„์น˜๋งŒ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ state๋ฅผ ๋ณด์กดํ•œ๋‹ค.

5. ๋ฆฌ์ŠคํŠธ์—์„œ state

์•„๋ž˜ ์ฝ”๋“œ์—์„œ ๋ฌธ์ œ๋Š” Contact ์ปดํฌ๋„ŒํŠธ์˜ expanded ๋ผ๋Š” state๊ฐ€ ์˜๋„์™€ ๋‹ค๋ฅด๊ฒŒ ๋‚จ์•„์žˆ๊ฒŒ ๋œ๋‹ค๋Š” ์ ์ด๋‹ค. "Alice" ์—ฐ๋ฝ์ฒ˜ ์ปดํฌ๋„ŒํŠธ์˜ expanded ๋ฅผ ์ฐธ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ์œ„์น˜๋ฅผ ๊ฑฐ๊พธ๋กœ ๋Œ๋ฆฌ๋ฉด ํ•ด๋‹น ์œ„์น˜๋กœ ์˜ค๊ฒŒ๋˜๋Š” "Taylor" ์ปดํฌ๋„ŒํŠธ์˜ expanded๊ฐ€ ์ฐธ์œผ๋กœ ์„ค์ •๋œ๋‹ค. ์ฆ‰ key๊ฐ’ ๋ณ€๊ฒฝ์— ๋”ฐ๋ฅธ ์ƒํƒœ ์ดˆ๊ธฐํ™”๊ฐ€ ์ ์šฉ์ด ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ.

export default function ContactList() {
  const [reverse, setReverse] = useState(false);

  const displayedContacts = [...contacts];
  if (reverse) {
    displayedContacts.reverse();
  }

  return (
    <>
      <label>
        <input
          type="checkbox"
          checked={reverse}
          onChange={e => {
            setReverse(e.target.checked)
          }}
        />{' '}
        Show in reverse order
      </label>
      <ul>
        {displayedContacts.map((contact, i) =>
          <li key={i}>
            <Contact contact={contact} />
          </li>
        )}
      </ul>
    </>
  );
}

์›์ธ์€ key๊ฐ’์„ ์ธ๋ฑ์Šค๋กœ ์ฃผ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—. ๋ฐฐ์—ด์˜ ์ฒซ ์ธ๋ฑ์Šค๋Š” Alice๊ฑฐ๋‚˜ Taylor๊ฑฐ๋‚˜ 0์ธ๊ฒƒ์€ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. ๊ทธ๋ž˜์„œ key๊ฐ’์ด ์œ ์ง€๋˜๋‹ˆ props๋กœ ์ „๋‹ฌ๋˜๋Š” contact ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ •๋ณด๋Š” ๋ฐ”๋€”์ง€๋ผ๋„, ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ state์ธ expanded๋Š” ์œ ์ง€๊ฐ€ ๋˜๋Š”๊ฒƒ. ๋”ฐ๋ผ์„œ key๊ฐ’์„ ๋ฐฐ์—ด ์ธ๋ฑ์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ์ง„์งœ ์ปดํฌ๋„ŒํŠธ์˜ key๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ’์œผ๋กœ(๊ฐ€๋ น contact.id) ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.