Kimsora✨
320x100
반응형

 Custom Hooks

개발자가 스스로 커스텀한 훅을 의미하며 이를 이용해 반복되는 로직을 함수로 뽑아내어 재사용할 수 있다

 

  1. 상태관리 로직의 재활용이 가능한 경우
  2. 클래스 컴포넌트보다 적은 양의 코드로 동일한 로직을 구현할 수 있는 경우

 

 

FriendStatus 컴포넌트는 사용자들이 온라인인지 오프라인인지 확인하고,

FriendListItem 컴포넌트는 사용자들의 상태에 따라 온라인이라면 초록색으로 표시하는 컴포넌트가 있다

이 두 컴포넌트는 정확하게 똑같이 쓰이는 로직이 존재한다

 

//FriendStatus : 친구가 online인지 offline인지 return하는 컴포넌트
function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

//FriendListItem : 친구가 online일 때 초록색으로 표시하는 컴포넌트
function FriendListItem(props) {
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

 

두 컴포넌트에서 사용하기 위해 동일하게 사용되고 있는 로직을 분리하여 함수 useFriendStatus로 만든다

 

Custom Hook을 정의할 때는 일종의 규칙이 있다

  • Custom Hook을 정의할 때는 함수 이름 앞에 use를 붙여야한다 
  • 대개의 경우 프로젝트 내의 hooks 디렉토리에 Custom Hook을 위치 시킨다
  • Custom Hook으로 만들 때 함수는 조건부 함수가 아니어야 한다
    =>즉 return 하는 값은 조건부여서는 안 된다  useFriendStatus Hook은 온라인 상태의 여부를 boolean 타입으로 반환하고  있다
function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

 

useFriendStatus Hook을 두 컴포넌트에 적용

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

코드 분할

React에서 코드 분할하는 방법은 dynamic import(동적 불러오기)를 사용하는 것이다

=>구문 분석 및 컴파일해야 하는 스크립트의 양을 최소화 시키기 위해 dynamic import 구문을 사용한다

Static Import

import 구문은 문서의 상위에 위치해야 하고 블록문 안에서는 위치할 수 없는 제약 사항이있다.

번들링 시 코드 구조를 분석해 모듈을 한 데 모으고 사용하지 않는 모듈은 제거하는 등의 작업을 하는데, 코드 구조가 간단하고 고정이 되어 있을 때에만 가능하다

/* 기존에는 파일의 최상위에서 import 지시자를 이용해 라이브러리 및 파일을 불러왔습니다. */
import moduleA from "library";

form.addEventListener("submit", e => {
  e.preventDefault();
  someFunction();
});

const someFunction = () => {
  /* 그리고 코드 중간에서 불러온 파일을 사용했습니다. */
}

Dynamic Import

일반적인 정적인 Module Import  필요한 시점 에 로드 할 수 있도록 도와준다

=>첫 페이지 진입시에 필요한 최소한의 코드만 다운 받고, 사용자가 특정 페이지나 위치에 도달할 때마다 코드를 로드 한다면, 첫 페이지의 초기 성능을 올릴 수 있다

불러온 moduleA 가 다른 곳에서 사용되지 않는 경우, 사용자가 form을 통해 양식을 제출한 경우에만 가져오도록 할 수 있다                then 함수를 사용해 필요한 코드만 가져온다 가져온 코드에 대한 모든 호출은 해당 함수 내부에 있어야 한다 
이 방식을 사용하면 번들링 시 분할된 코드(청크)를 지연 로딩시키거나 요청 시에 로딩할 수 있다
=>React.lazy 와 함께 사용할 수 있다.

form.addEventListener("submit", e => {
  e.preventDefault();
	/* 동적 불러오기는 이런 식으로 코드의 중간에 불러올 수 있게 됩니다. */
  import('library.moduleA')
    .then(module => module.default)
    .then(someFunction())
    .catch(handleError());
});

const someFunction = () => {
    /* moduleA를 여기서 사용합니다. */
}

React.lazy()

React.lazy 함수를 사용하면 dynamic import를 사용해 컴포넌트를 렌더링할 수 있다.

React는 SPA(Single-Page-Application)이므로 한 번에 사용하지 않는 컴포넌트까지 불러오는 단점이 있는데 React는 React.lazy를 통해 컴포넌트를 동적으로 import를 할 수 있기 때문에 이를 사용하면 초기 렌더링 지연시간을 어느정도 줄일 수 있게 된다

React.lazy로 감싼 컴포넌트는 단독으로 쓰일 수는 없고, React.suspense 컴포넌트의 하위에서 렌더링을 해야 한다

import Component from './Component';

/* React.lazy로 dynamic import를 감쌉니다. */
const Component = React.lazy(() => import('./Component'));

React.Suspense

대표적으로, 비동기작업을 진행하면서 발생하는 로딩시간을 기다리면서 처리할 작업들을 대체하는 것이고 특정 데이터를 사용하는 컴포넌트에 데이터가 준비되지 않았음을 알리는 역할을 수행한다.

웹 페이지를 불러오고 진입하는 단계인 Route에 이 두 기능을 적용시키는 것이 좋다

React를 사용할때 로딩 화면을 사용하는 경우를 생각해보면 비동기 네트워크 요청을 통해 데이터를 받아와서 화면에 보여지도록 하는 과정에서 사용하고 특히 처음에 컴포넌트가 렌더링 되는 과정에서 자주 사용한다.

/* suspense 기능을 사용하기 위해서는 import 해와야 합니다. */
import { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
			{/* 이런 식으로 React.lazy로 감싼 컴포넌트를 Suspense 컴포넌트의 하위에 렌더링합니다. */}
      <Suspense fallback={<div>Loading...</div>}>
				{/* Suspense 컴포넌트 하위에 여러 개의 lazy 컴포넌트를 렌더링시킬 수 있습니다. */}
        <OtherComponent />
				<AnotherComponent />
      </Suspense>
    </div>
  );
}

=>비동기로 작업되는 컴포넌트를 Suspense로 감싸고, 로딩 때 보여줄 화면을 fallback 속성으로 전달한다.

로딩화면을 생성하기 위한 useState와 같은 hook들이 생성될 필요가 없어졌다

728x90
반응형

'React' 카테고리의 다른 글

redux-toolkit  (0) 2022.12.19
Fragment/Portal  (0) 2022.12.04
useMemo/useCallback  (0) 2022.11.28
Virtual DOM/ React Diffing Algorithm  (0) 2022.11.28
Redux  (0) 2022.11.04
profile

Kimsora✨

@sorarar

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그

WH