함수형 컴포넌트 훅(Hook)(2)

박종현·2022년 5월 23일
0

React

목록 보기
5/7

useRef

  • React 컴포넌트는 기본적으로 State가 변할때 마다 다시 렌더링 된다
  • 함수형 컴포넌트는 함수이기 때문에 렌더링이 될 때 마다 다시 호출되게 된다 → 컴포넌트 함수가 다시 호출이 된다는 것은 함수 내부의 변수들이 모두 다시 초기화가 되고 함수의 모든 로직이 다시 실행된다는 것을 의미

다시 랜더링 되어도 동일한 참조값을 유지하려면?

컴포넌트 내부 변수의 저장공간이 필요하다. 이 때 사용하는 것이 useRef Hook이다.

useRef로 선언한 변수는 값이 변하더라도 렌더링이 일어나지 않고, 렌더링이 일어나더라도 값을 유지할 수 있다

const 변수명 = useRef(초기값)
  • 위와같이 useRef는 변수명과 초기값을 설정하여 선언할 수 있다
  • ref값을 사용할 경우 변수명.current 로 가져올 수 있다.
  • ref값을 변경하려면 변수명.current = ... 로 변경시킬 수 있다

정리

state 변화 → 렌더링 → 컴포넌트 내부 변수들 초기화

ref변화 → No 렌더링 → 변수들의 값이 유지됨

state의 변화 → 렌더링 → ref의 값 유지됨

예시

useRef() 작동 이해

import {useState, useRef, useEffect} from "react";

function App() {

    const [countState, set_countState] = useState(0);
    const countRef = useRef(0)
    let countVar = 0
    const totalRenderingCnt = useRef(0)

    useEffect(() => {
        totalRenderingCnt.current = totalRenderingCnt.current + 1;
        console.log("렌더링 수 : ", totalRenderingCnt.current)
    })

    function increaseCountState() {
        set_countState(countState + 1)
    }

    function increaseCountRef() {
        countRef.current = countRef.current + 1
        console.log("Ref : ",countRef);
    }

    function increaseCountVar() {
        countVar = countVar + 1;
        console.log("Var : ",countVar);
    }

    function pringResult() {
        console.log("state ; ", countState "ref : ", countRef.current, "var : ", countVar )
    }

    return (
        <div className="App">
            <p>State : {countState}</p>
            <p>Ref : {countRef.current}</p>
            <p>Var : {countVar}</p>
            <button onClick={increaseCountState}>State 증가</button>
            <button onClick={increaseCountRef}>Ref 증가</button>
            <button onClick={increaseCountVar}>Var 증가</button>
            <button onClick={pringResult}>state, ref, var 출력</button>

        </div>
    );
}

export default App;
  1. state 증가, ref 증가, var 증가 각 3회후 출력버튼

    • state값은 버튼을 클릭할 때마다 렌더링 되므로 화면에 표현됨
    • ref, var 값은 변화시켜도 렌더링 되지 않으므로 화면에 표시되지 않지만 콘솔창에 로그로 남겨짐

  2. state값 증가 (렌더링 유발)

    • state값을 증가시켜 렌더링이 일어난 결과 ref값은 유지되었으나 var 값은 함수 재호출로 인해 초기화 되는 것을 알 수 있다.

Dom 요소 접근(포커스)

import{useState, useRef, useEffect}from"react";

functionApp() {

		constinputRef = useRef();
		
		useEffect(() => {
				inputRef.current.focus()
		},[])
		
		
		functionlogin() {
		        alert(`welcome ${inputRef.current.value}!`)
		        inputRef.current.focus()
		    }
		
		return(
		        <divclassName="App">
		
		            <input ref={inputRef}type="text"placeholder="username"/>
		            <buttononClick={login}>login</button>
		
		        </div>
		    );
}

export defaultApp;
  • useRef로 특정 DOM 선택하기 : input 노드의 ref속성에 useRef()로 생성한 변수 입력 → 특정 컴포넌트에서 특정 DOM을 선택해야할 때 ref 속성을 사용해야하고, 함수형 컴포넌트에서 이를 설정할 때는 useRef를 사용하여 설정
  • useEffect로 최초 렌더링시 DOM에 접근한 ref 값에 포커스 하도록 설정

useContext

react에서 context api는 앱 안에서 전역적으로 사용되는 데이터들을 여러 컴포넌트들이 공유할 수 있는 방법을 제공해 준다

react에서의 일반적인 데이터 흐름은 부모 컴포넌트에서 자식 컴포넌트로props를 통해 전달된다.

  • 상위 컴포넌트에서 하위 컴포넌트로 props를 통해 데이터를 전달하는 과정을 prop Drilling이라고 한다
  • C, E 컴포넌트에서 App컴포넌트의 데이터를 필요하다고 가정하면, 중간의 컴포넌트는 해당 데이터가 필요하지 않음에도 불구하고 데이터가 거쳐가게 된다.
    • 코드 복잡성 증가

props 대신에 context를 사용해서 데이터를 공유하면 상위 컴포넌트에 있는 데이터를 모든 자녀 컴포넌트들이 useContext를 통해 데이터를 사용할 수 있게 된다.

단, context를 사용하면 컴포넌트를 재사용하기 어려워 질 수 있으므로 반드시 필요한 경우에만 사용한다.

context API를 사용하기 위해서는 Provider , Consumer , createContext 이렇게 세가지 개념을 알고 있으면 된다.

  • createContext : context 객체를 생성한다.
  • Provider : 생성한 context를 하위 컴포넌트에게 전달하는 역할을 한다.
  • Consumer : context의 변화를 감시하는 컴포넌트이다.

Context 예제

App.js

import React, { createContext } from "react";
import Children from "./Children";

// AppContext 객체를 생성한다.
export const AppContext = createContext();

const App = () => {
  const user = {
    name: "박종현",
    job: "백수"
  };

  return (
    <>
      <AppContext.Provider value={user}>
        <div>
          <Children />
        </div>
      </AppContext.Provider>
    </>
  );
};

export default App;

Children.js

  • <AppContext.Consumer> 태그로 컴포넌트를 감싸서 컨텍스트 적용
import React from "react";
import { AppContext } from "./App";

const Children = () => {
  return (
      <AppContext.Consumer>
        {(user) => (
          <>
            <h3>AppContext에 존재하는 값의 name은 {user.name}입니다.</h3>
            <h3>AppContext에 존재하는 값의 job은 {user.job}입니다.</h3>
          </>
        )}
      </AppContext.Consumer>
  );
};

export default Children;
  • 이 예제 에서는 하나의 컴포넌트에서만 context를 사용했지만 여러 컴포넌트에서 사용할 경우 코드가 점점 복잡해짐(중복 발생)

Children.js → useContext 를 적용

import React, { useContext } from "react";
import { AppContext } from "./App";

const Children = () => {
  // useContext를 이용해서 따로 불러온다.
  const user = useContext(AppContext);
  return (
    <>
      <h3>AppContext에 존재하는 값의 name은 {user.name}입니다.</h3>
      <h3>AppContext에 존재하는 값의 job은 {user.job}입니다.</h3>
    </>
  );
};

export default Children;

App.js 에서 Context를 생성하고 Provider를 통해 전달하는 코드는 그대로

AppContext 를 사용하는 과정이  const user = useContext(AppContext)를 통해 Context를 불러 온 후 바로 사용이 가능하게 바뀌었다.

따라서 useContext를 사용하면 기존의 Context 사용 방식보다 더 쉽고 간단하게 Context를 사용이 가능하고, 앞서 다뤘던 useState, useEffect와 조합해서 사용하기 쉽다는 장점이 있다

0개의 댓글