Daehyunii's Dev-blog

[데브코스] TIL-125 React, style, useMemo, useCallback, Custom Hook 본문

✏️ 2022. TIL/December (데브코스)

[데브코스] TIL-125 React, style, useMemo, useCallback, Custom Hook

Daehyunii 2022. 12. 19. 00:13
컴포넌트 스타일링

1. 스타일시트 적용

  외부 CSS파일을 import하여 사용하는 방법이다.

2. Inline style 적용

  동적으로 스타일을 결정하는 경우에 요소의 속성으로 style을 주는 방법이다.

3. CSS in JS 적용

  여러 라이브러리가 있는데 강의에서는 emotion이라는 라이브러리를 사용했다.

yarn add @emotion/react @emotion/styled
 

@emotion/styled

styled API for emotion. Latest version: 11.10.6, last published: a month ago. Start using @emotion/styled in your project by running `npm i @emotion/styled`. There are 7665 other projects in the npm registry using @emotion/styled.

www.npmjs.com

 

useMemo

 

  컴포넌트는 아래와 같은 상황에서 리렌더링 된다.

  • 함수 컴포넌트는 자신의 상태가 변경될 때
  • 부모 컴포넌트로부터 받는 prop이 변경될 때
  • 부모 컴포넌트의 상태가 변경될 때

  만약 연산 속도가 느린 컴포넌트라면 렌더링 시간이 오래 걸릴 것이다. 이러한 경우 최적화를 위해 useMemo를 사용하는 것이 필요하다.

두번째 인자로 배열을 넘겨주는데, 배열 안의 n이 변경 될 때만 sum()함수를 실행시키기 위해 useMemo 함수를 사용하여 다른 상태 값의 변경과 관계없이 독립적으로 실행하도록 만들어 주었다.

const result = useMemo(() => sum(n), [n])

 

React.memo

 

  부모 컴포넌트는 변경되었지만 자식 컴포넌트가 변경되지 않았을 때 리렌더링하지 않도록 도와주는 함수이다. 자식 컴포넌트에서 리렌더링되는 함수를 React.memo로 감싸주면 된다.

 

useCallback

 

  컴포넌트가 리렌더링될 때 함수가 다시 선언되는 것을 막기 위해 사용되는 hook이다. checkbox 하나를 클릭했는데 Checkbox 컴포넌트에 연결되어 있는 함수들이 전부 선언되는 문제를 useCallback을 사용해 해결할 수 있다.

...
const foodChange = useCallback((e) => setFoodOn(e.target.checked), [])
const clothesChange = useCallback((e) => setClothesOn(e.target.checked), [])
const shelterChange = useCallback((e) => setShelterOn(e.target.checked), [])

return (
    <div>
        <Checkbox ... onChange={foodChange} />
        <Checkbox ... onChange={clothesChange} />
        <Checkbox ... onChange={shelterChange} />
    </div>
)

 

Custom Hook

 

  사용자 정의 hook은 기존 hook을 조합해서 만들 수 있다. 이를 사용하면 코드의 중복을 줄일 수 있고 컴포넌트도 더 깔끔하게 사용할 수 있다.

import { useCallback, useState } from 'react';

const useToggle = (initialState = false) => {
  const [state, setState] = useState(initialState);
  const toggle = useCallback(() => setState((state) => !state), []);

  return [state, toggle];
};

export default useToggle;
import useToggle from './useToggle';

function App() {
  const [on, toggle] = useToggle();

  return (
    <div>
      <button onClick={toggle}>{on ? 'true' : 'false'}</button>
    </div>
  );
}

export default App;

 

오늘을 마무리 하며

 

  오늘은 앞서 말했던 문제점들에 내가 알고 있는 최적화에 도움을 주는 Hook들에 대해서 공부했다. 위에서 언급했듯이 리액트가 리렌더링 되는 경우는 3가지 경우이다. 자신의 컴포넌트 state가 변경되는 경우, 부모로 부터 받은 props가 변경된 경우, 부모 컴포넌트의 상태가 변경된 경우이다. 한 문장으로 정리하면 state가 변경되면 리렌더링된다. 그렇기 때문에 불필요한 리렌더링들이 많이 존재할 수밖에 없고 이를 해결하기 위해 useMemo, React.memo, useCallback을 통해 특정 값의 변경이 있는 경우에만 실행할 수 있도록 설정해주는 것이 필요하다. 즉, dependency를 잘 설정해 줄 필요가 있겠다. 그리고 이러한 최적화는 규모가 작으면 놓치기 쉬운 부분일 것이기 때문에 평소 간단한 코드를 작성할 때도 습관화 해 놓는것이 필요할 것 같다.