UseState와 UseRef를 이용한 렌더링 개선

성찬홍·2023년 6월 1일
0

Code Refactoring

목록 보기
1/5

렌더링 : 코드로 정의된 내용이 실제 브라우저 화면에 그려지는 과정

React 렌더링 시점

-> 대표적으로 아래 5가지 정도의 렌더링 상황이 있다.
1. state의 교체 ( useState , disaptch)
2. 부모 컴포넌트의 재렌더링
3. Root.render(…) 함수 호출 (react 18) / react18 이전은 ReactDOM.render(…)
4. props의 교체
5. 중앙 상태값 ( Redux,Mobx,Recoil, ConText Api 등)의 변화

이번에는 UseRef와 UseState를 다룰 예정이므로 state 교체에 따른 렌더링을 다룰 것입니다.

UseRef vs UseState

UseRef → 값이 변화할 때마다 리렌더링이 이루어지지 않는다.
UseState → 상태가 변화할 때마다 리렌더링이 이루어진다.

UseState

  • useState는 함수형 또는 클래스형 컴포넌트의 상태를 관리하고 , 변경할 수 있도록 도와주는 하나의 React Hook이다.
  • 아래와 같은 형태로 쓰이며, setValue를 통해서만 값변경이 가능하고, setValue를 통해 값이 변경될 때마다 리렌더링이 된다.
const [value,setValue]=useState(초기값)

UseRef

  • 저장공간 또는 DOM 요소에 접근하기 위해 사용되는 React Hook이다.
  • javaScript에서 querySelector 등의 함수를 사용하는데, React에서 DOM을 선택해야하는 상황에 qeurySelector처럼 사용하기 위한 react hook이다.
    + tip) querySelector는 실제 DOM을 가져오게 되는데, Rreact에서는 Virtual DOM을 그리기 때문에,
    React가 제어하고 있는 Virtual DOM 안에 있는 요소가 더 신뢰할만하다.)
  • useState와는 다르게 useRef로 관리되는 값은 값이 변해도 화면이 리렌더링되지 않는다.

코드 설명 ( 댓글 추가 기능 ) 문제점 및 개선 전/후 코드 설명

문제점 : 백엔드로 보낼 input의 value값을 onChange를 이용해 useState에 저장하였다.
이렇게 되면, 텍스가 입력될 때마다 리렌더링이 발생해 불필요한 리렌더링이 지속적으로 발생하여 성능에 좋지 못했다.
그래서 아래와 같이 useState를 useRef를 이용하여 개선시켜보았다.

개선 전 코드
(1) 댓글 input 박스에 텍스트를 입력한다.
(2) 입력시마다 useState에 텍스트가 저장된다.
(3) 버튼 클릭 시,useState에 저장되있는 텍스트를 api실행으로 백엔드에 보내준다.
(3) 텍스트값이 MYSQL에 INSERT된다
(4) MYSQL에 저장된 댓글을 불러와 클라이언트에 보여준다.

개선 후 코드
(1) 댓글 input 박스에 텍스트를 입력한다.
(2) 댓글 입력 완료 버튼 클릭 시 , useRef를 이용해 텍스트값을 추출한다.
(3) 추출 된 값을 백엔드로 보낸다.
(4) 텍스트 값이 MYSQL에 INSERT되고 , 댓글을 불러와 클라이언트에 보여준다.

& 수정 전 코드
// TS 코드
// (insertContext = api통신에 쓰여질 데이터)
const [insertContext, setInsertContext] = useState<string>("");

const handleContext = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInsertContext(e.target.value);
};

//text의 값을 백엔드로 보낸다.
const handleSubmit = (event: React.MouseEvent<HTMLButtonElement>) => {
    event.preventDefault();
    const axiosData = {
      CO_CONTEXT: insertContext,
      S_IDX,
    };
    const result = axiosInstance.post("/clubDetail/insertContext", axiosData);
		
		setInsertContext("");
  };

//JSX 코드
<input type="text" placeholder="댓글을 입력해주세요" 
			className="w-4/5  ml-1 border-y-neutral-800" 
			onChange={handleContext}
			value={insertContext}/>

현재 필요한 데이터는 버튼을 클릭했을 때, input value값이다.
하지만 위 코드에서는 텍스트가 변화할때마다 useState의 값이 변화하여,계속되어 불필요한 리렌더링이 발생하여 성능 저하의 요인이 된다.

& 수정 후 코드
// TS  
const insertText = useRef<HTMLInputElement>(null);

const handleSubmit = (event: React.MouseEvent<HTMLButtonElement>) => {
    const data = insertText.current?.value;
    event.preventDefault();
    const axiosData = {
      CO_CONTEXT: data,
      S_IDX,
    };
    const result = axiosInstance.post("/clubDetail/insertContext", axiosData);
    if(insertText.current){
      insertText.current.value='';
    }    
  };


// JSX
<input type="text" placeholder="  댓글을 입력해주세요"
className="w-4/5  ml-1 border-y-neutral-800" ref={insertText}/>

useRef를 이용하여 input value 값을 참조할 수 있게 변경하였다.
이렇게 하여 , 값의 변화에 따른 불필요한 리렌더링이 일어나지 않게 되어 성능 측면에서 더 좋아졌다.

정리

구글이나 네이버에서의 검색 기능을 사용할 때는,텍스트창의 value에 따라 지속적으로 결과를 보여줘야하기에, 리렌더링이 필요하기에 useState를 이용한 방법이 더 옳을 수 있다.

그러나 위와 같은 경우에는, 지속적인 변화에 따라 변화되는 것이 아닌 버튼을 눌렀을 때의 값만을 백엔드로 보낼 데이터만 필요하기에 useRef를 이용한 방법이 좀 더 효율이 좋다.

참고 사이트

https://yceffort.kr/2022/04/deep-dive-in-react-rendering

https://velog.io/@jinyoung985/React-useRef%EB%9E%80

profile
꾸준한 개발자

0개의 댓글