[20220601_useRef hook(1 - 변수관리)]

YunTrollpark·2022년 6월 1일
0

React

목록 보기
5/12

useRef 1: 변수관리

1. useRef란?

→ ref object는 { current: value } 생김 → 그리고 우리가 인자로 넣어준 초기값은 ref안에 있는 current에 저장 ↓

• ref object는 수정이 가능하기 때문에 언제든 우리가 원하는 값으로 수정가능! ↓

• 반환된 ref는 컴포넌트의 전생에주기를 통해 유지가 됨
→ 컴포넌트가 계속해서 렌더링되어도, 컴포넌트가 unmount되기 전꺼지는 값을 그대로 유지 가능

2. useRef는 언제 사용이 되는가?

1) 저장공간

• ref는 state와 비슷하게 어떠한 값을 저장해두는 공간으로 사용
• State의 변경하면 → 자동으로 컴포넌트가 렌더링 → (함수형 컴포넌트는 말그대로 함수라서 리렌더링을 하면 함수가 다시 불러지는거라서) 내부에있는 변수들이 다시 초기화 됨
→ 그래서 원하지 않는 렌더링때문에 곤혹을 겪음

그러면 State말고 ref에 저장하는건 무슨 차이?
• Ref의 값을 아무리 변경해도 → 컴포넌트는 다시 렌더링 ❌ → 그래서 변수들의 값이 유지 됨
• State의 변화(컴포넌트가 아무리 렌더링 되어도) → 그래도 Ref에 저장된 값은 유지됨
→ 그래서 변경시 렌더링 되지 말아야 하는 값을 다룰때 아주 유용!

2) Dom 요소에 접근

• input 요소를 클릭하지 않아도, focus를 주고 싶을 때 많이 사용
ex) 로그인 화면이 보여졌을때, id를 넣는 input을 굳이 클릭하지 않아도 자동적으로 focus가 되어있게 해주면, 바로 키보드를 사용해서 id를 입력할 수 있음!
→ Ref를 사용하면 손쉽게 input에 접근해서 이런 작업을 쉽게 할 수 있음!
→ 바닐라 자바스크립트의 Document.querySeletor()의 역할을 함

3. useState vs useRef 사용예시

1)useState 예시

import React, { useState } from 'react';

const App = () => {
  const [count, setCount] = useState(0); //count라는 State가 있고, 0으로 초기화
  
  console.log('🍎렌더링...'); //여기에 consosle로 확인하면 State가 변경될때마다 App이 console에 출력됨
  
  const increaseCountState = () => {
    setCount(count + 1); //이 함수는 불릴때마다 setCount를 사용해서 count를 하나씩 증가시켜줌
  };
  
  return(
    <div>
    <p>State: {count}</p> //count State를 보여주는 p태그
    <button onClick={increaseCountState}>State 올려</button> // 이 버튼을 누를때마다 inCreaseCountState함수가 불림
    //리액트에서 State가 변경된다는 것은 컴포넌트가 다시 렌더링 됨
    //이 컴포넌트는 함수형 컴포넌트라서 App이라는 함수가 다시 불려진다는 것
    </div>
  );
}

export default App;

2)useRef 예시

import React, { useState, useREf } from 'react';

const App = () => {
  const [count, setCount] = useState(0);
  const countRef = useRef(0);
  console.log(countRef); //console로 확인하면 {current: 0} 출력되는거 확인 가능
  //→ Ref는 하나의 object이고, Ref안에는 current라는 값이 있고, current안에는 우리가 설정한 초기값 0을 가짐!
  //그래서 Ref안에 있는 값에 접근하고 싶으면 countRef.current 이런식으로 접근!
  
  console.log('🍎렌더링...');
  
  const increaseCountState = () => {
    setCount(count + 1);
  };
  
  const increaseCountRef = () => {
    countRef.current = countRef.current + 1;
  }

  
  return(
    <div>
    <p>State: {count}</p> 
    <p>Ref {countRef.current}</p>
    <button onClick={increaseCountState}>State 올려</button>
    <button onClick={increaseCountRef}>Ref 올려</button>//버튼이 눌릴때마다 State가 아닌 Ref가 증가 되도록!

    </div>
  );
};

export default App;
여기서 알수있는 Ref의 장점은 만약 컴포넌트 안에 자주 바뀌는 값을 State안에 넣어 놓으면?
→ 값이 바뀔때마다 렌더링되고 또 렌더링 됨 → 이러면 성능에 안좋은 영향을 미침 → 여기서 State가 아니라 Ref를
사용해주면 값이 아무리 바껴도 렌더링을 발생시키지 않아서 성능에 좋음!

4. 컴포넌트 내부 변수 vs useRef

import React, { useState, useREf } from 'react';

const App = () => {
  const [renderer, setRenderer] = useState(0);
  const countRef = useRef(0);
  let countVar = 0;
 
  
  const increaseRef = () => {
  countRef.current = countRef.current + 1;
  };
    
  const increaseVar = () => {
  countVar = countVar + 1;
  };
  
  const doRendering = () => {
  setRenderer(renderer + 1);
  }
  
  //Ref의 변화도  렌더링 ❌ → 화면 업데이트 ❌
  //변수의 변화도 렌더링 ❌ → 화면 업데이트 ❌
  // → 화면을 업데이트 해주는 State가 필요함
  
  return(
    <div>
    <p>Ref: {countRef.current}</p>
    <p>Var: {countVar}</p>
    <button onClick={doRendering}>렌더</button> //누르면 UI에 반영하게끔
    <button onClick={increaseRef}>Ref 올려</button>
    <button onClick={increaseVar}>Var 올려</button>


// 이렇게 만들고 렌더 버튼을 누르면 Ref는 화면에 렌더링 되고, Var는 안됨
// 우리의 컴포넌트가 렌더링 된다는 것은 컴포넌트를 나타내는 함수가 다시 불린다는 것
// → 함수가 불리면 불릴때마다 함수내부의 변수가 초기화됨(함수가 불리때마다 countVar변수는 함수가 불릴때마다 0으로 초기화!)

// 하지만 Ref는 우리 컴포넌트가 계속 렌더링되어도 값을 유지
// → 왜냐하면 Ref의 값은 컴포넌트의 전생에주기를 통해 유지되기때문
// 이말인 즉슨 컴포넌트가 브라우저에 mounting된 시점부터 mount해제된 시점까지 같은 값 유지 가능
  );
};

export default App;

5. useRef 나쁜예시 vs 좋은예시

1) 나쁜예시

import React, { useState, useREf } from 'react';

const App = () => {
  const [count, setCount] = useState(1);
  const [renderCount, setRenderCount] = useState(1);
  
  useEffect (() => {
  console.log("렌더링!");
  setRenderCount(renderCount + 1);
  });
   
  //몇번 렌더링 됐는지 확인할때 이렇게 작성하면 무한루프 걸림...
  // 왜냐하면 "올려"버튼을 누르면 useState안에 setCount가 업데이트 되기 때문에 해당 useEffect가 불림
  //문제는 useEffect안에도 renderCount State를 업데이트 하는 코드가 있음
  //count State 업데이트 됐고 → useEffect 불렸고 → 그리고 renderCount도 업데이트 됨
  //→ 그러면 또 useEffect 불리고 → 또 renderCount불리고 이렇게 무한히 반복됨
  
  
  
  return(
    <div>
     <p>Count: {count}</p> //현재 카운트 값 출력
     <button onClick={() => setCount(count + 1)}>올려</button>
//버튼을 누를때마다 count state를 하나씩 증가시켜주는 버튼
    </div>
  );
};

export default App;

2) 좋은예시

import React, { useState, useREf } from 'react';

const App = () => {
  const [count, setCount] = useState(1);
  const renderCount = useRef(1);
  
  useEffect (() => {
    renderCount.current = renderCount.current + 1;
    console.log("렌더링 수:", rednerCount.current);
  });
  //이렇게 작성하면 console에 "올려"버튼을 누를때마다 렌더링수가 무한루프에 걸리지 않고 잘 나옴
  // 이유는 ref는 리렌더링을 발생시키지 않음
   
  return(
    <div>
     <p>Count: {count}</p> //현재 카운트 값 출력
     <button onClick={() => setCount(count + 1)}>올려</button>
    </div>
  );
};

export default App;

결론

useRef는 변화를 감지함, 하지만 그 변화가 렌더링을 발생시키면 안되는 어떤 값을 다룰때 유용하게 사용가능!
profile
코딩으로 세상에 이야기하는 개발자

0개의 댓글