본문 바로가기
내일배움캠프/Today I Learned

[TIL 2023.06.20] React Hooks useContext / useCallback / useMemo

by 괴코딩 2023. 6. 21.

💻오늘 배운 내용

useContext

전역 데이터를 관리하는 api

  • createContext : context 생성
  • Consumer : context 변화 감지
  • Provider : context 전달(to 하위 컴포넌트)

1. context 폴더 > FamilyContext.js 생성

import { createContext } from "react";

// 여기서 null은 초기값
export const FamilyContext = createContext(null);

2. props를 가장 처음 전달하던 컴포넌트에서 FamilyContext를 import해주고 자식컴포넌트를 <Provider>로 감싸준다.

    이때 전달할 데이터를 객체 형태로 전달한다. 

import React from "react";
import Father from "./Father";
import { FamilyContext } from "../context/FamilyContext";

function GrandFather() {
  const houseName = "스파르타";
  const pocketMoney = 10000;

  return (
    <FamilyContext.Provider value={{ houseName, pocketMoney }}>
      <Father />
    </FamilyContext.Provider>
  );
}

export default GrandFather;

3. props를 전달하기만 하던 컴포넌트에서는 useContext hook을 쓰면 아무것도 안해도 됨

import React from "react";
import Child from "./Child";

function Father() {
  return <Child />;
}

export default Father;

4. consumer로서 FamilyContext를 import해주고 내려받은 정보를 인자로 받아서 사용

import React, { useContext } from "react";
import { FamilyContext } from "../context/FamilyContext";

function Child({ houseName, pocketMoney }) {

  return (
    <div>
      나는 이 집안의 막내에요.
      <br />
      할아버지가 우리 집 이름은 <span style={stressedWord}>{data.houseName}</span>
      라고 하셨어요.
      <br />
      게다가 용돈도 <span style={stressedWord}>{data.pocketMoney}</span>원만큼이나
      주셨답니다.
    </div>
  );
}

export default Child;

 

useContext 사용 시 주의점

prop drilling 방지하고 손쉽게 전역 데이터를 관리할 수 있다는 장점은 있지만 

Provider에서 제공한 value가 달라진다면 useContext를 사용하고 있는 모든 컴포넌트가 리렌더링 된다.

>>최적화 문제가 발생할 수 있기 때문에 value 부분을 항상 신경써주어야 한다.

 

React 최적화 ( React.memo / useCallback / useMemo )

 

1] React.memo

부모 컴포넌트가 리렌더링 되면 자식컴포넌트는 모두 리렌더링 된다.

> 이를 방지 하기 위한 것이 React.memo

 

부모 컴포넌트의 state의 변경으로 인해 props가 변경이 일어나지 않는 한 컴포넌트는 리렌더링 되지 않는다.

이것을 component memoization이라도 한다.

사용예제) export 할 때 React.memo()를 붙여주면 된다.

export default React.memo(컴포넌트 이름);

* 메모이제이션을 했는데도 리렌더링이 되는 경우?

함수형 컴포넌트를 사용하기 때문이다. 함수도 객체의 한 종류.

따라서 부모 컴포넌트가 리렌더링 되면 모양은 같더라도 다시 만들어지면서 그 주솟값이 달라지고

이에 따라 하위 컴포넌트는 props가 변경됐다고 인식하기 때문에 리렌더링 될 수있다.

 

 

그래서! 함수를 메모리 공간에 저장해놓고, 특정 조건이 아닌 경우엔 변경되지 않도록 할 때 

사용하는 hook이 아래의 useCallback

 

2] useCallback

함수를 메모리 공간에 저장해놓고, 특정 조건이 아닌 경우엔 변경되지 않도록 할 때 사용하는 hook

React.memo는 컴포넌트를 memoization 했다면, useCallback은 인자로 들어오는 함수 자체를 memoization한다.

// 변경 전
const initCount = () => {
  setCount(0);
};

// 변경 후
const initCount = useCallback(() => {
  setCount(0);
}, []);

useCallback이 count가 0일 때의 시점을 기준으로 메모리에 함수를 저장하기 위해서는 dependency array가 필요하다.

 

3] useMemo

동일한 값을 반환하는 함수를 계속 호출해야 하면 필요없는 렌더링을 한다고 볼 수 있다.

그래서 React는 맨 처음 해당 값을 반환할 때 그 값을 특별한 곳(메모리)에 저장하는 hook을 만들었는데 그것이 useMemo.

이미 저장한 값을 단순히 꺼내와서 시용한다. => 캐싱을 한다

 

사용예제)

// as-is
const value = 반환할_함수();

// to-be
const value = useMemo(()=> {
	return 반환할_함수()
}, [dependencyArray]);

dependency Array의 값이 변경 될 때만 "반환할 함수"가 호출되고,

그 외의 경우에는 memoization 해놨던 값을 가져오기만 한다.

 

 

React.memo => component를 memoization

useCallback => function을 memoization

useMemo => value를 memoization

 

그러나 남발하게 되면 별도의 메모리 확보를 너무나 많이 하게 되기 때문에 오히려 성능이 악화될 수 있다.

필요할 때만 쓰기!

 

🧐궁금점과 부족한 내용

api의 의미

리액트 훅의 함수를 가리켜 api라는 말을 많이 사용하는데

 

여태 api라 함은 서버와 클라이언트 간의 그 어떤 연결고리? 정도로 인식해왔다.

 

'Application Programming Interface'

운영체제와 응용프로그램 사이의 통신에 사용되는 언어나 메시지 형식

 

가게의 점원 같은 역할,  API = '중간 전달자'

 

ㄲeact hook은 Class 형태였던 Component를 function을 통해 만들 수 있게 해주는 API이다.

그런데 나는 이것도 헷갈리기 때문에 API란 HTML 요소에 접근해서 수정할 수 있는 함수 정도로 이해해두자..

 

📋레퍼런스

https://ukcasso.tistory.com/86

반응형