Salangdung_i의 기록

제어/비제어 컴포넌트(1) SSOT원칙 본문

WEB FRONT END/React

제어/비제어 컴포넌트(1) SSOT원칙

Salangdung_i 2024. 9. 1. 20:29
728x90
요약

키오스크 프로젝트의 CS 인입이 발생했다.
현상 : 키보드 컴포넌트에서 이전에 입력한 값이 input에 왕창 찍히는 현상이 발생
확인 : 키보드에서 입력받은 text를 setState로 관리하고, 이 state가 변경될 때마다 useRef로 값을 넣어주고 그 값을 input value로 넘겨줬다. useRef 특성상 값의 변화에 따라 화면을 랜더링 하지 못하고, 이 때문에 useRef의 값이 화면에 그려지는 시점에서  이전에 입력했던 text가 input value에 들어가면서 발생한 현상이다. 

const [text, setText] = useState<string>('');
const input = useRef<string>('');

useEffect(() => {
   input.current.value = text;
}, [text]);

return (
   <div>
    <Input value={input.current.value}/>
    <Keyboard onChange={e=>setText(e.target.value)}
  </div>)

 

문제는 해결했지만 왜 키보드 컴포넌트를 비제어 컴포넌트로 구현하려고 했는지, 제어/비제어 컴포넌트에 대한 이해와 나만의 개발 가이드를 만들고 싶어 스터디 한 과정에 대한 기록이다. 
 

 

제어 비제어 컴포넌트를 스터디 주제 선정 이유

키오스크 키보드 창에서 데이터를 입력을 때 간헐적으로 이전에 입력했던 값들이 찍히는 현상이 발생했다. 코드를 뜯어보니 키보드에서 입력한 데이터를 onChange로 받아 저장하고 이 값을 input창에는 ref로 넣어주는 이상한(?) 코드가 있었다. 이전 개발 히스토리를 몰라 개발자의 의도를 찾아 헤매었었다. 검색하다 보니 키오스크는 컴퓨터만큼 성능이 좋지 않아 리랜더링이 자주 발생하면 성능 이슈가 있을 수도 있다는 글을 읽고 비제어 컴포넌트로 구현하려 했던 건가 하는 생각이 들었었다. 이김에 제어/비제어 컴포넌트에 대해 공부하고 나만의 사용 가이드를 만들고 싶어졌다.   

 

신뢰 가능한 단일 출처 (SSOT: Single Source Of Truth)

애플리케이션에서  데이터를 하나의 장소(출처)에서만 관리하고, 모든 컴포넌트나 시스템이 이 데이터를 참조하도록 하는 원칙이다. 이는 데이터의 일관성을 유지하고 오류를 줄이기 위해 매우 중요하다. 

React에서 SSOT 개념은 제어(Controlled)와 비제어(Uncontrolled) 컴포넌트의 개념과 밀접하게 연결되어 있다. 이 두 가지 개념을 통해 SSOT를 어떻게 구현하고, 어떤 상황에서 사용하는지를 알아보자.

 

제어 컴포넌트의 정의

제어 컴포넌트는 React에 상태(state)의해 값이 제어되는 입력 폼 엘리먼트를 말한다.

HTML에서 <input>, <textarea>, <select>와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트한다. React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 useState에 의해 업데이트된다. 이 컴포넌트는 사용자의 입력이나 다른 이벤트에 따라 변화하는 값이 React의 상태에 의해 관리되며, 이 상태가 단일 출처로 작동한다.

function ControlledInput() {
  const [value, setValue] = useState("");  // 상태로 관리

  const handleChange = (event) => {
    setValue(event.target.value);  // 상태를 업데이트
  };

  return (
    <input type="text" value={value} onChange={handleChange} />
  );
}

value는 React의 상태로 관리되며, 이 상태가 SSOT로 작동한다. 다른 컴포넌트에서 이 값을 필요로 하면, 동일한 상태를 참조하여 데이터 일관성을 유지할 수 있다.

 

비제어 컴포넌트의 정의

비제어 컴포넌트는 React에서 DOM 요소가 자체적으로 상태를 관리하는 방식이다. 즉, 값이 DOM의 내부 상태로 관리되며, React는 이 상태를 직접적으로 제어하지 않는다. 모든 state 업데이트에 대한 이벤트 핸들러를 작성하는 대신 비제어 컴포넌트를 만들려면 ref를 사용하여 DOM에서 폼 값을 가져올 수 있다.

function UncontrolledInput() {
  const inputRef = useRef(null);  // DOM에 직접 접근

  const handleSubmit = () => {
    alert(`입력된 값: ${inputRef.current.value}`);
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleSubmit}>Submit</button>
    </div>
  );
}

inputRef.current.value는 React의 상태로 관리되지 않고, DOM의 자체 상태에 저장된다. 이 값은 React가 제어하지 않으므로, 다른 컴포넌트에서 이 값을 일관되게 참조하기 어렵다.

 

비제어 컴포넌트의 SSOT원칙에 왜 위배되는 걸까?

공부를 하다 보니 의문이 들었다. 비제어 컴포넌트에서 ref를 사용하여 상태를 저장하는 경우, 그 상태가 한 곳에 저장되는데 왜 SSOT원칙에 부합하지 않는다는 걸까란 는 생각이 들었다. 

비제어 컴포넌트에서 ref를 사용하여 데이터를 관리하는 경우, 데이터가 한 곳에 저장되기는 하지만, 그 데이터는 React의 상태 관리 체계와 분리되어 있어 SSOT 원칙에 부합하지 않는다. SSOT의 핵심은 데이터가 중앙에서 관리되고, 모든 관련된 컴포넌트가 이 데이터를 일관되게 참조하고 반영하는 것이다.

더보기
  • 데이터 관리의 분산: 비제어 컴포넌트에서는 데이터가 React의 상태가 아닌, 각 DOM 요소의 내부 상태로 관리되므로, 이 데이터는 여러 출처에서 관리된다고 볼 수 있습니다. 이는 SSOT 원칙에 위배됩니다.
  • 데이터의 일관성 문제: 만약 여러 컴포넌트가 동일한 데이터에 접근해야 한다면, 비제어 컴포넌트에서의 데이터는 DOM에서 직접 가져와야 합니다. 이 과정에서 데이터가 일관되지 않을 수 있으며, 데이터 흐름이 복잡해질 수 있습니다.
  • 데이터 접근성의 어려움: 비제어 컴포넌트에서는 React의 상태를 통해 데이터를 관리하지 않으므로, 다른 컴포넌트나 로직에서 이 데이터를 활용하려면 DOM을 직접 접근해야 하는 복잡성이 생깁니다. 이는 데이터를 중앙에서 관리하는 SSOT 원칙과 반대되는 개념입니다.

반면, ref에 저장된 데이터는 React의 상태 관리 체계 외부에 존재하므로, 데이터 일관성을 유지하기 어렵고, 다른 컴포넌트와 데이터를 공유하거나 제어하기도 까다롭다. 따라서, 중요한 애플리케이션 상태를 관리할 때는 React 상태를 사용하는 제어 컴포넌트를 사용하는 것이 일반적으로 더 적절하다.

 

ref와 React 상태의 차이 비교

  제어 컴포넌트 비제어 컴포넌트
렌더링 관계  React의 상태는 리액트가 관리하는 데이터입니다. 상태가 변경되면 해당 상태에 의존하는 모든 컴포넌트가 다시 렌더링됩니다. 따라서 UI와 상태가 항상 일관되게 동기화됩니다 ref는 DOM 요소나 클래스 컴포넌트의 인스턴스를 참조할 수 있도록 React가 제공하는 기능입니다. 하지만 ref는 값이 변경되더라도 React의 렌더링 사이클에 영향을 주지 않습니다. 즉, ref에 저장된 데이터가 변경되어도 컴포넌트는 자동으로 다시 렌더링되지 않으며, UI가 이 데이터를 반영하지 않을 수 있습니다.
데이터 흐름과 제어 상태는 컴포넌트의 데이터 흐름을 제어하며, 상태가 변경되면 React가 자동으로 이 변화를 관리하여 컴포넌트와 UI를 일관되게 유지합니다. ref는 단순히 값을 저장하기 위한 컨테이너 역할을 합니다. React는 ref의 값이 어떻게 변경되는지 추적하지 않으며, 이로 인해 데이터가 어떻게 변화하고 있는지 명확하지 않을 수 있습니다. 이는 데이터 흐름이 명확하게 제어되지 않음을 의미합니다.
SSOT 상태는 컴포넌트의 중앙 집중 관리 포인트로 작용하며, 데이터는 이 상태에서 관리됩니다. 다른 컴포넌트들도 이 상태를 공유하거나 props로 받아 사용할 수 있으므로 데이터의 일관성을 유지할 수 있습니다.  ref는 컴포넌트 내부에서만 접근 가능한 데이터 저장소로 사용될 수 있으며, 다른 컴포넌트에서 이를 참조하거나 공유하기 어렵습니다. 따라서 데이터가 여러 출처에서 관리될 수 있다는 문제가 발생할 수 있습니다.


다음 포스팅에서는 제어/비제어 컴포넌트를 사용해야 하는 시점과 React 공식문서에서 추천하는 formik 에 대해 알아보겠습니다.! 

 

[React 공식] 제어 컴포넌트 

 

폼 – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

React-제어-컴포넌트와-비제어-컴포넌트

 

[React] 제어 컴포넌트와 비제어 컴포넌트

제어 컴포넌트 비제어 컴포넌트를 살펴보기 전에 먼저 신뢰 가능 단일 출처에 대해서 알아보고자 한다.제어컴포넌트를 통해서 React에서는 이 문제를 해결했기 때문이다.하나의 상태는 한 곳에

velog.io

728x90

'WEB FRONT END > React' 카테고리의 다른 글

[기술면접] Lifecycle Method  (0) 2022.04.10
[기술면접] : useMemo와 useCallback  (0) 2022.04.10
[기술면접] Virtual DOM?  (0) 2022.03.30
React Hooks  (0) 2022.03.17
라이프사이클 메서드  (0) 2022.02.10