ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1-5 React Hooks - useRef
    React 숙련주차 2023. 4. 30. 17:44

    useRef
    ref는 reference를 의미한다. 참조라는 뜻을 가진다.
    useRef 활용방법
    1. 저장공간
    2. DOM요소 접근

    1. useRef hook소개
    (어딘가에 저장한)DOM요소에 접근할 수 있도록 하는 React Hook. 

    HTML과 JavaScript를 사용할때 특정DOM을 선택하기위해 사용했던 방법
    //(1)getElemtById 이용
    const divTag = document.getElementById('#myDiv');

    //(2)querySelector 이용
    const divTag2 = document.querySelector('#myDiv');

    리액트에서도 Dom을 선택해야할 상황이 생기기 마련이다. 예를들면 화면이 렌더링되자마자
    특정 input태그가 focusing이 돼야하는 경우(네이버 들어가면 검색 인풋창에 커서가 깜빡이고 있는상태)가 그것이다.
    그럴 경우 useRef hook을 사용한다.

    2. useRef hook 사용방법

    import { useRef } from "react";
    import "./App.css";
    
    function App() {
      const ref = useRef("초기값");
      console.log("ref", ref);
    
      ref.current = "변경값";
      console.log("ref2", ref);
      return <div>App</div>;
    }
    
    export default App;

    변수 설정하듯이 const ref = useRef("초기값");의 형태를 만든다.

    ref의 형태를 console창에 찍어보면 객체형태로 나오는것을 볼 수 있고,

    그 ref의 current를 ref.current = "변경값";의 형태로 바꾸고 ref를 다시 찍어보면,

    객체형태로 {current: '변경값'}으로 바뀐것을 볼 수 있다.

    (중요) 이렇게 설정된 ref값은 컴포넌트가 계속해서 렌더링 되어도 unmount전까지 값을 유지한다.

    이러한 특징 때문에 useRef는두가지 용도로 사용된다.

    1. 저장공간
    a. state와 비슷한 역할을 한다. 하지만 state는 변화가 일어나면 다시 렌더링이 일어난다(이유: 함수형 컴포넌트이기 때문에 함수가 다시 그려진다). 내부 변수들은 초기화된다.
    b. ref에 저장한 값은 렌더링을 일으키지 않는다. 즉, ref의 값 변화가 일어나도 렌더링으로 인해 내부 변수들이 초기화되는것을 막을 수 있다.
    c. 컴포넌트가 100번 렌더링→ref에 저장한 값은 유지된다.
    d. 정리하면
    i. state는 리렌더링이 꼭 필요한 값을 다룰 때 사용한다.
    ii. ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다.

    2. DOM
    a. 렌더링 되자마자 특정 input이 focusing되어야한다면 uesRef를 사용한다.

    예제코드로 특징 살펴보기
    state와 ref의 차이점

    import { useRef, useState } from "react";
    import "./App.css";
    
    function App() {
      const [count, setCount] = useState(0);
      const countRef = useRef(0);
    
      const plusStateCountButtonHandler = () => {
        setCount(count + 1);
      };
    
      const plusRefCountButtonHandler = () => {
        countRef.current++;
        console.log(countRef.current);
      };
    
      return (
        <>
          <div>
            state 영역입니다. {count} <br />
            <button onClick={plusStateCountButtonHandler}>state 증가</button>
          </div>
          <div>
            ref 영역입니다. {countRef.current}
            <br />
            <button onClick={plusRefCountButtonHandler}>ref 증가</button>
          </div>
        </>
      );
    }
    
    export default App;

     

    DOM에 접근하는 useRef(아까말한 네이버 인풋창 포커싱처럼)

    아이디인풋과 패스워드인풋을 만들어놓고, 아이디 인풋창에 포커싱 되도록 해보자.
    일단 화면이 처음 렌더링 될때 어떤 작업을 하는 useEffect를 만들도록 한다.
    dependency array도 일단 빈 배열로 같이 넣는다.
    그리고 jsx문법이 들어가는 곳에 idRef라는 상수를 useRef('')로 선언한 후
    포커싱 되게 하고싶은 input태그안에 ref={idRef}를 넣어서 연결시켜준다.
    그리고 useEffect함수안에 idRef.current.focus();를 해주면 비로소 아이디 인풋창에 포커싱이 된다.

    import { useEffect, useRef } from "react";
    import "./App.css";
    
    function App() {
      const idRef = useRef("");
    
      //화면이 렌더링 될 때, 어떤 작업을 하고싶다면 useEffect
      useEffect(() => {
        idRef.current.focus();
      }, []);
    
      return (
        <>
          <div>
            아이디 : <input type="text" ref={idRef} />
          </div>
          <div>
            패스워드 : <input type="password" />
          </div>
        </>
      );
    }
    
    export default App;

    미션
    위 코드에서 아이디가 열자리 입력되면 자동으로 패스워드 필드로 이동하도록 코드짜기

    1. 아이디가 10자리가 입력되는지 트래킹하는 요소를 넣어야한다. useState이용
    const [id, setId] = useState('');선언하고
    아래 아이디인풋태그안에 value={id} onChange={(event)=>{setId(event.target.value)}}를 추가해준다.
    이렇게하면 아이디인풋창안에 타이핑 하나하나할때마다 페이지에 문자가 적히는데 이걸 렌더링이된다라고 한다.

    2. 인풋창에 열자리가 입력될때 패스워드인풋창으로 포커싱하는 작업을 하기 위해
     useEffect(()=>{}, [])를 하나 더 선언한다.

    useEffect(() => {
        if(id.length >= 10){
          pwRef.current.focus();
        }
      }, [id]);

    만약 id의 길이가 10보다 크거나 같을때 패스워드인풋창으로 포커싱해주는데, 
    useEffect는 id라는 state가 바뀔때마다 발동되어야하기때문에 dependency array안에도 id를 넣어줘야만한다.

     

    이렇게 저장하고 페이지에서 아이디인풋창에 열자리를 타이핑해보면 패스워드인풋창으로 포커싱되는것을 볼 수 있다.

    import { useEffect, useRef, useState } from "react";
    import "./App.css";
    
    function App() {
      const idRef = useRef("");
      const pwRef = useRef("");
    
      const [id, setId] = useState("");
    
      //화면이 렌더링 될 때, 어떤 작업을 하고싶다면 useEffect
      useEffect(() => {
        idRef.current.focus();
      }, []);
    
      useEffect(() => {
        if (id.length >= 10) {
          pwRef.current.focus();
        }
      }, [id]);
    
      return (
        <>
          <div>
            아이디 :{" "}
            <input
              value={id}
              onChange={(event) => {
                setId(event.target.value);
              }}
              type="text"
              ref={idRef}
            />
          </div>
          <div>
            패스워드 : <input type="password" ref={pwRef} />
          </div>
        </>
      );
    }
    
    export default App;


    단순하게 생각해서 useEffect대신에  onChange를 이용해서 input태그안에 
    if()문을 넣어서 할수있지않을까 하는 생각이 들 수도 있다.

    import { useEffect, useRef, useState } from "react";
    import "./App.css";
    
    function App() {
      const idRef = useRef("");
      const pwRef = useRef("");
    
      const [id, setId] = useState("");
    
      useEffect(() => {
        idRef.current.focus();
      }, []);
    
      return (
        <>
          <div>
            아이디 :{" "}
            <input
              value={id}
              onChange={(event) => {
                setId(event.target.value);
                if(id.length >=10) {
                  pwRef.current.focus();
                }
              }}
              type="text"
              ref={idRef}
            />
          </div>
          <div>
            패스워드 : <input type="password" ref={pwRef} />
          </div>
        </>
      );
    }
    
    export default App;

     

    하지만 이렇게 하면 열한자리를 입력해야 아래로 포커싱되는것을 볼 수 있다.
    그 이유는 리액트는 state를 배치업데이트방식으로 적용했다.
    그래서setId에서 state를 set한것이 if문안에서 아직 반영이 안되기때문에 id.length값이 한박자 늦게 들어오게된다.

     

    ⭐state는 배치업데이트방식이다⭐

    'React 숙련주차' 카테고리의 다른 글

    1-7 React Hooks - React.memo  (1) 2023.05.02
    1-6 React Hooks - useContext  (0) 2023.04.30
    1-4 React Hooks - useEffect  (0) 2023.04.30
    1-3 React Hooks - useState  (0) 2023.04.29
    1-2 Styled Components (전역 스타일링)  (0) 2023.04.29
Designed by Tistory.