HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📝
학습 TIL
/
📝
49일차 배운 것 정리
📝

49일차 배운 것 정리

대주제
React
작성완료
작성완료
전날 정리 노트 이동
📝
48일차 배운 것 정리
다음 정리 노트 이동
📝
50일차 배운 것 정리
주제
useCallback
useMemo
customHook
로그인/회원가입
storybook
날짜
May 26, 2022

목차

목차1. 리액트 2화1. 컴포넌트 스타일링 - 13m1-1. 스타일 시트를 이용하는 방법1-2. inline을 통한 Css 적용1-3. CSS in JS2. useMemo + React.memo- 7m + 3m2-1 useMemo2-2. React.memo(공식문서 link)3. useCallback- (공식문서) 6m4. customHook - 13m5. storybook- 13m6. 사용사례 (로그인, 회원가입) - 30m2.1.1-1.2.2-1.

1. 리액트 2화

1. 컴포넌트 스타일링 - 13m

1-1. 스타일 시트를 이용하는 방법

  • 일반적인 css 파일을 import 해서 적용하는 방법
    • 생략

1-2. inline을 통한 Css 적용

💡
prop을 통해 동적으로 스타일이 변경될 경우 사용

1-3. CSS in JS

  • StyledComponent, Emotion 등 사용가능
    • Emotion을 통한 실습 (Emotion)
      • 기본적으로 Emotion 코드를 적용하기 위해서 Babel을 사용하는데, CRA환경에서는 babelrc를 통한 설정이 불가하다.
        • 따라서 플래그마 (/** @jsxImportSource @emotion/react */)를 코드 상단에 작성하여, 파서에게 알려주는 방법으로 해결할 수 있다.
        • 단 매번 모든 파일에 작성하는 것은 번거롭기 때문에 이를 자동화하여 사용
          • 1) eject를 통해 설정 파일을 불러내어 babelrc를 사용하기
          • 2) craco 라이브러리를 통해 설정을 overide하여 적용하기
            • 설치 ( npm i -D @craco/craco )
            • babel 설정을 craco.config.js 안에서 작성
              • 코드
                module.exports = { babel: { presets: ["@emotion/babel-preset-css-prop"], }, };
            • package.json에서 실행 스크립트를 craco start로 변경
      • Emotion의 css 모듈을 통한 스타일링
        • EmotionBox 예제
          import React from "react"; import { css } from "@emotion/react"; const style = css` color: blue; background-color: red; width: 150px; height: 150px; `; const EmotionBox = () => { return ( <div css={style}> <AnotherComponent /> </div> ); }; const anotherStyle = css({ textDecoration: "underline", }); const AnotherComponent = () => ( <div css={anotherStyle}>Some text with an underline.</div> ); export default EmotionBox;
      • Emotion의 styled 모듈을 통한 styledcompoent 방식의 스타일링
        • EmotionStyledBox 예제
          import styled from "@emotion/styled"; const EmotionStyledBox = styled.div` color: white; background-color: royalblue; width: 150px; height: 150px; `; export default EmotionStyledBox;

2. useMemo + React.memo- 7m + 3m

react 문서링크
💡
값비싼 계산의 함수의 경우는 useMemo를 통해 memoization 하여, 관련된 상태의 변경 시에만 새로 계산하여, 컴포넌트를 리렌더링하도록하고, 부모컴포넌트의 변경과 관련 없는 자식 컴포넌트의 리렌더링 방지를 위해 React.memo를 사용할 수 있다.
함수 컴포넌트의 리렌더링 상황
  • 자신의 상태가 변경될 때
  • 부모 컴포넌트로 부터 받는 props가 변경될 때
  • 부모 컴포넌트의 상태가 변경될 때 ⇒ React.memo

2-1 useMemo

💡
useMemo는 memoization을 통해 함수컴포넌트의 렌더링 최적화를 위해 사용
첫번째 인자로 값비싼 비용의 함수를 콜백형태로 받고, 두번째 인자로 의존성 배열을 넣어 사용 useMemo( () ⇒ func , [] )
 
!! 연산속도가 느린 컴포넌트가 있다면, 리렌더링 상황에 취약하다.
  • 값 비싼 연산을 가진 컴포넌트 예제
    • 코드
      xport default function UseMemoCompoent({ label, n }) { const expensiveComputeSum = (n) => { let result = 0; console.log("게산 시작"); for (let i = 0; i < n; i++) { result = result + n; } console.log("게산 끝"); return result; }; const result = useMemo(() => expensiveComputeSum(n), [n]);
주의 useMemo로 전달된 함수는 렌더링 중에 실행된다. 사이드 이펙트의 경우 useEffect에서 처리할 것!
주의 useMemo는 필수가 아니라 값비싼 계산과 같은 필요한 부분에 적용하는 것 (메모리 비용들기 때문에)
 

2-2. React.memo(공식문서 link)

💡
React.memo는 고차컴포넌트(HOC)로, 동일한 props를 통해 같은 결과를 렌더링한다면, 이전에 Memoization 해두었던 컴포넌트를 그대로 재사용한다.
  • 주의 React.memo로 감싸더라도, 내부 컴포넌트에서 useState, useReducer, useContext등을 통해 state를 변경한다면 리렌더링 된다.
  • 주의 부모로 부터 받는 props가 변할 경우에 당연히 리렌더링 한다.
  • 심화 props는 기본적으로 얕은 비교를 수행한다.
    • 깊은 비교로 리렌더링 여부를 결정하기 위해서는 두번째 인자로 custom비교함수를 넣어주어 사용할 수 있다.
    • React.memo(ChildComponent, areDeepEquaul)

3. useCallback- (공식문서) 6m

💡
컴포넌트에서 props을 통해 함수를 받게 될 때, 해당 함수는 항상 재정의되기 때문에 React.memo를 적용하여도 리렌더링 된다. 이를 방지하기 위해, 함수 자체를 memoization하여, props으로 넘겨주어도 재정의되어 리렌더링 되는 것을 막을 수 있다.
  • 사용상황
    • 하나의 부모요소의 여러개의 자식요소가 있을 때, 특정 자식요소의 변경이 모든 자식요소의 리렌더링 되는 것을 방지할 때 사용
  • 즉 여러 자식요소 중 변경이 있는 자식요소만을 리렌더링하고 싶을 때에는
    • React.memo를 통해 자식 컴포넌트를 memoization하고,
    • props로 넘어오는 함수들은 부모컴포넌트의 변화로 리렌더링시 재정의되지 않도록 useCallback을 통해 memoization 해주어야 한다.

4. customHook - 13m

💡
반복되는 hooks의 사용을 custom 모듈화 하여 가독성있게 표현할 수 있다.
  • useToggle 사례
    • toggle상태와 toggle변경함수를 리턴하는 hooks
    • 코드비교
      // Before const [appleOn, setAppleOn] = useState(false); const [bananaOn, setBananaOn] = useState(false); const [caramelOn, setCaramelOn] = useState(false); const onAppleChange = useCallback((e) => { setAppleOn(e.target.checked); }, []); const onBananaChange = useCallback((e) => { setBananaOn(e.target.checked); }, []); const onCaramelChange = useCallback((e) => { setCaramelOn(e.target.checked); }, []); // After const [appleOn, setAppleOn] = useToggle(false); const [bananaOn, setBananaOn] = useToggle(false); const [caramelOn, setCaramelOn] = useToggle(false);
  • useHover 사례 (이벤트 제어)
    • 특정 element를 지칭하는 ref와 해당 element의 hover 여부를 반환하는 Hooks
      • hooks에서 hover Event 처리
        • 코드
          const useHover = () => { const [state, setState] = useState(false); const ref = useRef(null); const handleMouseOver = useCallback(() => setState(true), []); const handleMouseOut = useCallback(() => setState(false), []); useEffect(() => { const element = ref.current; if (element) { element.addEventListener("mouseover", handleMouseOver); element.addEventListener("mouseout", handleMouseOut); } return () => { element.removeEventListener("mouseover", handleMouseOver); element.removeEventListener("mouseout", handleMouseOut); }; }, [ref, handleMouseOver, handleMouseOut]); return [ref, state]; }; export default useHover;
  • useKeyPress 사례 (이벤트 제어)
    • 특정 key가 눌렸을 때만 true를 리턴하는 hooks
      • hooks에서 keypress Event처리
      • 코드
        import { useState, useCallback, useEffect } from "react"; const useKeyPress = (targetKey) => { const [state, setState] = useState(false); const handleKeyDown = useCallback( ({ key }) => { if (key === targetKey) { setState(true); } }, [targetKey] ); const handleKeyUp = useCallback( ({ key }) => { if (key === targetKey) { setState(false); } }, [targetKey] ); useEffect(() => { window.addEventListener("keydown", handleKeyDown); window.addEventListener("keyup", handleKeyUp); return () => { window.removeEventListener("keydown", handleKeyDown); window.removeEventListener("keyup", handleKeyUp); }; }, [handleKeyDown, handleKeyUp]); return [targetKey, state]; }; export default useKeyPress;

5. storybook- 13m

  • 설치
    • CRA시
      • $ npx -p @storybook/cli sb init

6. 사용사례 (로그인, 회원가입) - 30m

 

2.

1.

1-1.

2.

2-1.