⌨️ 제어 컴포넌트 vs 비제어 컴포넌트

리액트 컴포넌트

1. 📝 Form 태그 엘리먼트 이해

1.1. 🧱 Input 태그의 특징

  • ==input 태그는 Form 태그 엘리먼트의 대표적인 예시==
  • ==value attribute를 통해 자체적인 데이터를 가짐==
    • 사용자 입력 값은 ==value attribute에 저장됨==
    • 즉, 사용자 입력 데이터는 ==DOM==에 저장

2. 🛡️ 신뢰 가능한 단일 출처 (Single Source of Truth)

2.1. 📍 개념 정의

  • 하나의 상태를 나타내는 state는 ==한 곳에만 존재==해야 함
    • 여러 컴포넌트에서 사용 시: ==props==, ==Context API==, ==Redux 등을 활용==

2.2. ⚠️ 문제점: 데이터 불일치 가능성

  • Input의 ==value==를 변수로 저장하여 사용할 경우
    • ==input 자체의 value==와 변수 간의 ==데이터 불일치 발생 가능==
    • 특히 규모가 커질수록 최신 값에 대한 ==신뢰도 하락==

2.3. 🦸 React의 해결책: 제어 컴포넌트

  • React가 ==value==와 state 간의 일치함을 보장

3. 🚦 제어 컴포넌트 (Controlled Component)

3.1. 🎯 정의

  • React에 의해 값이 제어되는 입력 Form 엘리먼트

3.2. ⚙️ 동작 방식

  • React state와 input의 ==value prop을 연결==

  • ==onChange 이벤트 핸들러를 통해 입력 값을 state에 반영==

  • 변경된 state는 span tag 등에 렌더링됨

    function ControlledComponent() {
      const [name, setName] = React.useState('');
     
      const handleChange = (event) => {
        setName(event.target.value);
      };
     
      return (
        <div>
          <input type="text" value={name} onChange={handleChange} />
          <span>{name}</span>
        </div>
      );
    }

3.3. ✅ 특징

  • ==input== ==value==와 React의 state는 ==항상 최신 값으로 일치==
  • 매 입력마다 ==re-rendering 발생==

4. 🚫 비제어 컴포넌트 (Uncontrolled Component)

4.1. 📜 특징

  • Form data는 DOM 자체에서 다뤄짐
  • DOM이 신뢰 가능한 출처를 유지
  • 전통적인 HTML Form 태그와 동일하게 동작

4.2. ⚙️ 동작 방식

  • ==ref==를 사용하여 DOM 엘리먼트에 직접 접근

  • 사용자 입력 값은 DOM에 저장됨

  • 필요 시 ==ref==를 통해 input의 ==value==를 가져옴

    function UncontrolledComponent() {
      const inputRef = React.useRef(null);
     
      const handleSubmit = (event) => {
        event.preventDefault();
        console.log('Input Value:', inputRef.current.value);
      };
     
      return (
        <form onSubmit={handleSubmit}>
          <input type="text" ref={inputRef} />
          <button type="submit">Submit</button>
        </form>
      );
    }

4.3. ✅ 특징

  • React가 데이터 일치함을 보장하지 않음
  • state 관리 X → ==re-rendering 발생 X==
  • ==ref==를 통해 DOM에 직접 접근

5. 🆚 제어 vs 비제어 컴포넌트 비교

구분제어 컴포넌트비제어 컴포넌트
값 관리 주체ReactDOM
값 동기화O (value와 state 동기화)X
최신 값 유지OX
Re-renderingO (매 입력마다 발생)X
장점최신 값 보장, 즉각적인 유효성 검사 및 피드백성능 이점, 간단한 구현
단점매 입력마다 Re-rendering 발생데이터 불일치 가능성, DOM 직접 접근 필요
주요 사용 사례즉각적인 validation, 입력 값에 따른 동적 UI 변경간단한 Form, 성능 최적화가 중요한 경우

6. 🎯 활용 시나리오

6.1. ✅ 제어 컴포넌트

  • 매 입력마다 특정 동작 필요 시
    • 입력 값 렌더링
    • 즉각적인 validation 및 피드백
      • 디테일한 피드백이 필요한 경우

6.2. ⛔ 비제어 컴포넌트

  • 최신 값이 굳이 필요하지 않은 경우
  • 렌더링 성능 이슈 발생 시

7. 📝 결론

  • Form tag elements는 DOM에 사용자 입력을 저장
  • Input의 value를 다른 곳에 저장하면 값 불일치 발생 가능성 ↑
  • 제어 컴포넌트는 value와 state를 동기화하여 최신 값 보장
  • 제어/비제어 컴포넌트는 장단점을 가지므로 상황에 맞게 선택 필요

대본

안녕하세요 오늘 테코톡발표를 하게 된 프론트엔드 후이입니다 반갑습니다제가 오늘 발표할 주제는 제어 컴포넌트와 비제어 컴포넌트입니다저희가 개발을 하며 Form을 다루는 일이 많은데요그 때 마다 자주 접하게 되는 단어가 바로 이 제어 컴포넌트와 비제어 컴포넌트인데요오늘 한번 최선을 다해서 발표해보도록 하겠습니다목차입니다일단 첫 번째로 제어 컴포넌트와 비제어 컴포넌트를 말하기 전에 Form tag elements에 대해서 먼저 말하고그리고 신뢰 가능한 단일 출처라는 단어를 문장에 대해서어떠한 뜻인지 먼저 설명을 하고그러고나서 제어 컴포넌트, 비제어 컴포넌트를 얘기하고마무리하도록 하겠습니다네 input 태그가 있습니다.input 태그는 전통적인 HTML 태그를 생각해 주시면 되시고자바스크립트 통해서 동작하고 있습니다input 태그는 Form 태그 엘리먼트의 대표적인 특성 중 하나죠태그 중 하나죠친구로는 select, textarearadio 등이 있는데 이 친구들은 다 집에 보내고오늘은 input을 대표로 한번 얘기해보도록 하겠습니다이 Form 태그 엘리먼트들은 조금 독특한 성질이 하나 있는데바로 value attribute를 통해서 자체적인 데이터를 갖는다는 겁니다여기 보시면 작고 귀여운 input 태그가 있죠지금 입력이 없어서 value가 빈 String입니다근데 여기에 안녕하세요라는 입력을 주면 어떻게 될까요근데 여기에 안녕하세요라는 입력을 주면 어떻게 될까요여러분들도 다 아시다시피value가 사용자 입력값으로 변하게 됩니다사용자가 입력한 값으로 value attribute로 변한다는 말은 당연한 말이죠사용자가 입력한 값으로 value attribute로 변한다는 말은 당연한 말이죠당연한 말을 조금 다르게 말해 볼 수 있을 것 같아요사용자가 입력한 값으로 value attribute가 바뀐다라는 말은 사용자가 입력한 값이 value attribute에 저장된다라고 말할 수 있겠죠근데 value attribute는 input 태그가 있잖아요Input 태그는 DOM에 존재하죠그 말은즉 input을 통한 사용자입력데이터는 DOM에 저장된다라고 할 수 있습니다제가 하고 싶었던 말은 이겁니다input을 통한 사용자 입력 데이터는 DOM에 저장된다이거를 말하고 싶어가지고 제가 이렇게 돌려 돌려 얘기했습니다그러면 이제 제어 컴포넌트에 대해서 얘기할 준비가 됐습니다제어 컴포넌트 react 공식 문서입니다마지막 문장을 보시면 React에 의해 값이 제어되는 입력 Form 엘리먼트를제어 컴포넌트라고 한대요굉장히 심플하죠전통적인 input 태그는 사용자가 직접 input의 값을 조작하고그걸 DOM이 그것을 저장했는데React는 그거를 본인이 직접 제어를 해준데요그러면 이거를 어떻게 하게 되는지알아보러 가기 전에 여기 눈에 띄는 문장이 하나 있습니다바로 신뢰 가능한 단일 출처 라는 말인데요저는 이거를 처음 봤을 때좀 마음에 와닿지가 않았어요이게 무슨 뜻일까라는 생각이 들어 가지고 찾아봤었는데여러분들도 아마 같은 마음일 거라 생각하고이것에 대해서 한번 알아보도록 하겠습니다신뢰 가능한 단일출처라는 말은 제가 만든 말이 아니고요실제로 있는 말인데 이걸 다 다양하게 쓰고있어요DB에서도 쓰이고Redux에서도 쓰인 말인데저는 React만을 생각하고 말하겠습니다이걸 단순하게 말하면하나의 상태를 나타내는 state는한 곳에만 존재해야 한다는 뜻입니다저희가 만약에 어떤 state가 있는데그것을 여러 component에서 사용된다 그러면 어떻게 하나요그것을 여러 component에서 사용된다 그러면 어떻게 하나요props로 내려주거나 context api혹은 redux 같은 전역 상태 관리 툴을 사용해 가지고해당 state에 접근할 수 있도록 하겠죠이러한 모든 노력들이 하나의 상태는한 곳에만 존재하고그걸 사용하고 싶은 사람들은 거기에 접근해서 하도록 하는 것이었습니다이게 어쨌다는 걸까요아까 봤던 input 태그를 다시 한번 하나의 상태는한 곳에만 존재해야 한다이게 어쨌다는 걸까요아까 봤던 input 태그를 다시 한번 보도록 하겠습니다네 input 태그입니다 얘는 아까 말했듯이본인이 독자적인 데이터를 갖고 있죠value attribute를 통해서요얘는 신뢰 가능한 단일 출처라고 할 수 있습니다왜냐 이 입력에 있는값을 갖고 싶으면 이 엘리먼트에 접근해서 value attribute를 통해서 가져오면항상 최신의 입력값을 가져올 수 있죠그래서 신뢰가 가능합니다그리고 현재까지는 단일추출 왜냐하면은이 input이 한 곳에만 존재하고그것에 접근해서 가져오는 것인데요지금까지는 단일 출처라고 했었습니다그런데 만약에 저희가 개발을 하다가 저input의 value를 어딘가에서 변수로 저장해서사용하게 됐다고 한번 상상을 해 주세요name이라는 변수가 있고input의 값이 입력될 때마다 input 밸류가 변하게 됩니다그럼 지금 어떻게 됐나요input이 원래 가지고 있던 밸류가 하나가 있고이제 자바스크립트 코드상에 존재하는 메인 변수가 하나 됐죠처음에는 신뢰 가능한 단일 출처를 하는데이제 신뢰하기 조금 커지게 한두 개의 출처가 됐습니다저 이게 만약에 우리가 작은 앱을 개발하고 나 혼자 한다면저 이게 만약에 우리가 작은 앱을 개발하고 나 혼자 한다면어떻게 이 데이터가 일치함을 잘 노력한다면할 수 있을 것 같아요근데 만약에 이 앱이 복잡해지고규모가 커지고다양한 개발자들이 다 같이 하게 된다면내가 이 input value를 사용한다고 했을 때이게 최신화된 값인지실제 사용자 입력과 정확하게 일치하는지확신하기 어려울 것 같아요이거를 누가 조금 대신 해줬으면 좋겠어요누가 이걸 일치함을 보장해줘가지고나는 마음 편하게 사용할 수 있으면 좋겠어요누구그런 사람 없나? 짜잔 React 등장React가 이 2개로 나눠진 값을 늘 최신의 값으로일치함을 보장을 해주겠대요내가 해줄게! 어떻게?제어 컴포넌트를 통해서 해주나 봐요아 그러면 제어 컴포넌트를 통해두 개의 출처가 된 값이 항상 일치함을 보장해도데이터가 불 일치할 염려없이 사용할 수 있게 해준다는 소리구나데이터가 불 일치할 염려없이 사용할 수 있게 해준다는 소리구나그러면 이제 제어 컴포넌트가 어떻게 사용되는지코드를 보면서 한번 알아보도록 하겠습니다제어 컴포넌트의 대표적인 코드입니다name이라는 React state가 있고요그리고 state는 input의 value prop을 통해 넘겨집니다그리고 input의 값이 바뀔 때마다즉 사용자가 값을 입력할 때마다 입력된 값이 name에 set 됩니다그리고 set 된 네임은 span tag에 렌더링되게 되죠변경 된 input value가 매번 state로 push 되니까input의 value와 react의 value는항상 최신의 값으로 일치함이 보장됩니다그리고 하나또 특징적인 것은 매 입력마다 state가 변경 되기 때문에매 입력마다 re-rendering이 발생하게 됩니다다음으로 또 비제어 컴포넌트에 대해서 한번 알아보도록 하겠어요제어 컴포넌트도 공식 문서를 봤으니까 비제어 컴포넌트도 공식 문서라면 봐야죠근데 첫 줄부터 제어 컴포넌트를 사용하는게 좋대요비제어 컴포넌트가 많이 서운할 것 같은데한번 읽어보겠습니다제어 컴포넌트에서 form data는 react 컴포넌트에서 다뤄집니다방금 전까지 저희가 했던 얘기죠그리고 비제어 컴포넌트는 DOM 자체에서 데이터가 다뤄집니다이거 어디서 들어본 말인 것 같아요또 비제어 컴포넌트는 DOM의 신뢰 가능한 출처를 유지한대요이것도 어디서 들어본 것 같아요사실은 비제어 컴포넌트는 전통적인 HTML 홈 태그입니다저희가 일반적으로 사용했던 방식과똑같은 방식으로 동작이 되는데React에 사용할 때는 약간 사용법에 차이점이 있습니다그것에 대해서 한번 알아보겠습니다비제어 컴포넌트 코드입니다. 이 return 되는 jsx 엘리먼트를 보시면제어 컴포넌트와 조금 차이가 있죠눈에 띄는 게 저 ref인데제어 컴포넌트 저 자리에 onChange가 있었잖아요 이 ref는비제어 컴포넌트를 사용할 때 굉장히 중요한 녀석입니다따라서 ref에 대해서 한번 가볍게 알아보고 가도록 하겠습니다따라서 ref에 대해서 한번 가볍게 알아보고 가도록 하겠습니다ref란 리스트에서 값을 담는상자 같은 느낌으로 생각해 주시면 좋겠습니다컴포넌트 마운트 시점에 ref에current property에 엘리먼트가 대입이 되고컴포넌트가 re-rendering 되더라도ref는 값을 유지하고 있습니다그래서 약간 컴포넌트에해당 컴포넌트 전역 변수 같은 느낌으로 사용하시면 되겠습니다다시 한번 코드를 보겠습니다사용자가 값에 input과 input사이의 값을 입력하고 submit을 하게 되면handleSubmit이 표출됩니다handleSubmit은input ref에 current에 담긴 value를 console.log 하고 있습니다흐름을 보시면 알겠지만React가 여기서 값에 관여하는 바가 전혀 없습니다사용자 입력으로 DOM이 직접 조작되고해당 값이 필요할 때ref를 통해 input의 value를 pull 하고 있습니다가져오고 있죠비제어 컴포넌트로 input의 value를 사용하게 되면React가 데이터가 항상 일치함을 보장하지 못합니다또 state 로 관리하지 않기 때문에re-rendering이 발생하지 않는다는 특징이 있습니다그렇다면 제어 컴포넌트와비제어 컴포넌트에 대해서 한번 정리를 하고가보도록 하겠습니다제어 컴포넌트는 React가 값을 관리 하고요사용자 입력이 항상 state로 push되기 때문에최신화 값이 유지됩니다그리고 즉 input의 상태를 나타내는 state가항상 일치하죠그리고 입력마다 re-rendering이 발생합니다비제어 컴포넌트는 DOM이 값을 저장하고값이 필요할 때엘리먼트에직접 접근해서 가져와야 됩니다그렇기 때문에 React가 관여하는 바가 없기 때문에React가 값이 항상 일치함을 보장해주진 못해요근데 state를 사용하지 않기 때문에re-rendering이 발생하지 않습니다그러면 지금까지 알아봤던 제어 컴포넌트와비제어 컴포넌트의 특성을 사용해서어떤 곳에 사용은 한번 좋은지 알아보겠습니다그렇죠 제어 컴포넌트는 항상 최신화 값이 보장된다고 했죠그렇죠 제어 컴포넌트는 항상 최신화 값이 보장된다고 했죠그리고 왜 입력마다 re-rendering이 발생한다고 했습니다따라서 매 입력마다 입력 박스로 어떤 동작을 해야 하는 경우그럴 때 사용하면 좋은데그런 예시로 입력 값을 다른 곳에입력하자마자 렌더링해야 되는 경우그리고 사용자 입력에 대해서즉각적인 validation에서 피드백을 해야 되는 경우특히 좀 디테일한 피드백을 해야 되는 경우에 제어 컴포넌트를 사용하였습니다비제어 컴포넌트는 원하는 시점에값을 가져온다는 특징이 있습니다매 입력마다 re-rendering이 발생하지 않는다는특징도 있는데따라서 매 입력마다 최신의 값이 굳이 필요하지 않은 경우그런 경우와 만약에 렌더링마다복잡한 현상이 발생하는 경우에는비제어 컴포넌트를 사용하는 것을 고려해보면 좋습니다최종적으로 정리를 한번 해보겠습니다form tag elements는 DOM에 사용자 입력을 저장한다input의 value를 다른 곳에 저장을 사용하면값이 일치함을 신뢰하기 어려워진다제어 컴포넌트는 value와 state를 동기화 함으로써항상 최신의 값을 보장한다제어 컴포넌트와 비제어 컴포넌트는 각각 장단점이 있으니사용처에 맞게 선택하면 된다발표해서 다루지 않았던 내용은제어 컴포넌트와 비제어 컴포넌트의 세부적인 사용 예시에 대해서는 다루지 않았고요이거는 제가 말씀드렸던제가 말했던 제어 컴포넌트와 비제어 컴포넌트에 특징에 대해서 생각해 보시면사용할 때 어떤 거를 사용해야 할지생각할 수 있을 겁니다그리고 제어 컴포넌트의성능 최적화 부분은 제가 준비한 주제와는 좀 맞지 않는 것 같아서제외를 했습니다발표를 준비하며 참고 했던 자료들입니다그러면 이제 발표를 마치도록 하겠습니다 감사합니다