메모이제이션, Memoization

state가 바뀌면 안의 컴포넌트가 다시 만들어지면서 화면이 다시 그려지는데
그 안에 있는 자식, 변수, 함수는 다시만들어지나??
이론상으로는 된다고 했는데 실제로 한번 보자 + 이게 메모가 되는가 <- 이걸 메모이제이션이라고한다

한번 코드들을 통해서 보자

import { useState } from "react";
import MemoizationPresenterPage from "./presenter";
export default function MemoizationContainerPage() {
  console.log("컨테이너가 렌더링 됩니다!");

  let countLet = 0;
  const [countState, setCountState] = useState(0);

  function onClickCountLet() {
    console.log(countLet + 1);
    // countLet = countLet + 1;
    countLet += 1;
  }

  function onClickCountState() {
    console.log(countState + 1);
    setCountState(countState + 1);
  }

  return (
    <>
      <div>=================</div>
      <div>이것은 컨테이너 입니다!</div>
      <div>카운트(let): {countLet} </div>
      <button onClick={onClickCountLet}>카운트(let) + 1 올리기!!</button>

      <div>카운트(state): {countState} </div>
      <button onClick={onClickCountState}>카운트(state) + 1 올리기!!</button>

      <div>=================</div>
      <MemoizationPresenterPage />
    </>
  );
}
export default function MemoizationPresenterPage() {
    console.log("프리젠터가 렌더링 됩니다!")
  return (
    <>
      <div>=================</div>
      <div>이것은 프리젠터 입니다!</div>
      <div>=================</div>
    </>
  );
}

Cotainer(부모) presenter(자식)으로 나눠보고
부모가 바뀌면 자식이 어떻게 되나 보면 된다.
버튼을 만들어서 let과 state를 이용해서 카운트가 1씩 증가하게 만들었다
그리고 console.log를 이용해서 어떤곳이 렌더링되는지 써놓음

Let의 경우 카운트는 증가하지만 화면에 반영은 안된다

State의 경우 누를때마다 숫자가 올라가고, 컨테이너, 프리젠터를 다시 그려준다.

let은 변수만 증가, 화면은 다시 안그려주고, State는 화면을 다시 그려준다.

근데 프리젠터까지 바꾼다, 프리젠터는 바꾼게 없는데도말이다

react developer tools

체크를 하기위해 react developer tools를 깔아보자

설치하면 개발자 콘솔에서 이렇게 볼 수 있다.

거기서 profiler -톱니바퀴를 누르면 렌더링되는 대상을 볼 수 있다. 지금은 모든 부분이 표시된다

이후 상단에 버튼을 누르면 기록도할수있다

그러고나서 멈춰서 보면 어떻게 렌더링이 되는지 볼 수 있다.
회색깔 부분은 렌더링이 다시 되지 않은 부분을 의미한다(레이아웃이나 app은 가만히 있었던걸 볼수 있음)
그 와중에 컨테이너와 프리젠터가 다시 렌더링 된걸 볼 수 있다.

그럼 메모이제이션을 통해 프리젠터를 다시 렌더링되지 않게 하자

import { memo } from "react";
function MemoizationPresenterPage() {
  console.log("프리젠터가 렌더링 됩니다!");
  return (
    <>
      <div>=================</div>
      <div>이것은 프리젠터 입니다!</div>
      <div>=================</div>
    </>
  );
}

export default memo(MemoizationPresenterPage);

memo를 리액트에서 받아오고, 페이지를 memo로 감싸야한다.

실제로 콘솔에서도 다시 안불러오고있다. 프로파일러에서도 볼까??

프리젠터페이지는 다시 렌더링을 하지 않는 것을 볼 수 있다 오오😮😮😮

그런데 이렇게 memo를 해놔도 변경되야할때가 있을것이다. props같은게 넘어갈경우를 예로볼 수 있다.

근데 변수들도 다시만들어지는지 궁금해진다

  const randomValue = Math.random();
  console.log(randomValue);

랜덤한 숫자를 가져오게 하는 상수를 만들어보자

실제로 렌더링 될때마다 randomValue가 다시 실행되는 것을 볼 수 있다.

hooks(usestate useEffect등등) 은 리렌더링이 된다고 하더라도 기존값이 날라가지 않고 남아있다.
(카운트 올렸다고 초기화 안되는거 봤으니깐)
그래서 함수형 컴포넌트가 가능한 이유가 이것이기도 하다

state가 다시 만들어지면서 새로그려지기 때문에 random값도 나오지만 let또한 초기화되면서 다시 1이 나오게된다.

useMemo & useCallback

그래서 hooks들은 걱정할 필요가 없다. 근데 함수가 다시만들어지는 문제가 생기게된다.

  • 변수와 함수를 유지시키는 방법이 있다.

-변수 , useMemo

유지시키는 대신 state를 쓰면 되긴 한다 하지만 알아두면 나쁠건 없다

import { useMemo} from "react";
    const randomValue = useMemo(() => {
        return Math.random();
    }, [])
  console.log(randomValue);

복잡한 알고리즘을 돌려서 값을 저장해야할때 useMemo를 사용해서 계속 다시 계산되지 않게 해주면 좋다, 하지만 많이는 사용되지 않는다

근데 useMemo도 결국 use로 시작하는hook이므로 그래서 리렌더링되지 않는다고 생각하면된다.

-함수 , useCallback

import { useCallback, useMemo, useState } from "react";

  const onClickCountLet = useCallback(() => {
    console.log(countLet + 1);
    // countLet = countLet + 1;
    countLet += 1;
  }, []);

  const onClickCountState = useCallback(() => {
    console.log(countState + 1);
    setCountState(countState + 1);
  }, []);

주의할점 :

근데 이렇게하면 onClickCountState안에있는 countState까지 같이 저장되서 1이 바뀌지 않게 된다. 그럼 사실상 작동을 안한다는 소리

  setCountState((prev) => prev + 1);

prev, 실행할때마다 이전값을 꺼내와서 할 수 있게 해준다.


그럼 리렌더링은 되지 않지만(랜덤값이 바뀌지 않는거를 볼 수있음) 근데 숫자는 알아서 올라간다는 것을 볼 수 있다.

그럼 뒤에 [])는 뭘까? 재기억 할 수 있게 하는 의존생 배열인데 []안에 넣으면 바뀌는 값을 넣을 수 있다.

근데 이렇게 막 아무거나 다 적용시키면 안되고 의존성배열에 추가할 필요가 1,2개 이하인 것들만 적용시키는 것이 좋다.

+++++ 핵심은 성능도 성능이지만 유지보수가 중요하다. 0.1초를 빨리 하는거보단 유지보수가 좀 더 쉬운게 좋다
예시 20줄 코드 -> 4줄로 짤 수 있음
이게 더 좋아보이지만 아무도 모르고 자기밖에 모른다 : 그럼 차라리 20줄이 이득 왜냐하면 협업해야되니까, 실제로도 이렇게 돌아감, 항상 유지보수가 중요하다는 것을 알 것

만약 쓰지 않아도 presenter로 props로 넘긴다면 렌더링도 다시된다.

memo기능도 모든 곳에 사용하지 않아도 된다.
근데 반드시 필요한 부분이 있다.

예를들어서
https://medium.com/@freshmilkdev/reactjs-render-optimization-for-collapsible-material-ui-long-list-with-checkboxes-231b36892e20

이런식으로 체크박스 하나만 느려질 때 사용할 수 있다.

반응형 디자인

Wappalyzer

사이트에 적용된 기술을 확인할 수 있다.

직방을 보자

이런식으로 적용된 것을 볼 수 있다.

반응형 디자인

반응형 디자인이 그래서 뭔가

사이트가 작아지면 크기도 작아지는것을 의미한다.

개발자도구 -> 핸드폰 모양을 누르면 모바일 사이즈로 볼 수 있다.
화면 상단을 보면 핸드폰기종(사이즈가 다름) 을 볼 수 있다.

그럼 크기가 달라져도 화면이 정상적으로 나와야한다.

아이폰 6,7,8 기준으로 만들었는데 만약 더 큰 사이즈가 나온다? 그럼 그거에 맞게 화면이 커져야한다.
늘리는건 쉽다.
근데 반대로 큰 화면에서 만든 것을 작은화면으로 봐야하면 깨질 수 있다. 그림같은경우는 퍼센트로 나오겠지만 기준을 잡는 것이 중요하다.

-> 그래서 작은사이즈로 만들고 크게 키우게 하는 것이 좋다.
(가장 작은 사이즈 기준을 정하고 그에 맞는 반응형을 지정하자)
-> 아이폰 5에서 되서 그걸 점점늘려가서 잘 반응할 수 있도록

실제 코드로 만들어보자

import styled from "@emotion/styled";

const Wrapper = styled.div`
  width: 1000px;
  height: 1000px;
  background-color: red;

  @media 태블릿사이즈 {
    width: 500px;
    height: 500px;
    background-color: green;
  }
  @media 모바일사이즈 {
    width: 100px;
    height: 100px;
    background-color: blue;
  }
`;
export default function ResponsiveDesignPage() {
  return <Wrapper>상자</Wrapper>;
}

@media를 통해서 같은곳에 세가지 다른 css를 적용시켰다

본래의 1000px짜리를 만들었다가 태블릿사이즈가되면 500px로 +알파, 거기서 또 모바일이라면 100px로 +알파

이렇게 하나하나 다 만들어야되는 것이다.

이런 과정이 개발 과정에 다툼이 생기기 쉽다.
웹페이지 같은걸 사이즈를 줄여서 크기가 줄어든다고 모바일에서 적용이 되는 것이 아니다.

반응형이 무조건최고인가?
트렌트는 반응형이 맞다 근데 모든 사이트를 반응형으로 만들어야하는 것은 아니다.

네이버나 쿠팡의 경우는 반응형이 아닌 적응형이다

사이트 크기가 줄어들면 창도 줄어든다
이런데같은 경우는 들어가는 내용이 많아서 적용하기 어려울 수 있기때문(디자인의경우도)

이런곳의 공통점은 가운데만 있고(이미지 제외)

작은 사이즈의 모니터에서 꽉 차게 보이는 부분이 가운데 부분인 것이다. 이게 자기들이 정해둔 최소사이즈인것.

그럼 어떤 사이즈를 기준으로 줄여야하나???
-> 서비스마다 다르게된다.

일반적인 케이스를 보면

부트스트랩
표준 제공 사이즈가 있다. css관련 대표 라이브러리라고 생각하면된다.

사람들이 많이 사용하다보니 표준이 있다. css탭으로 가보면

네가지로 구분했고 여기서 3가지로 만든다면 태블릿과 중간기기 데스크탑을 합치면된다.

이 숫자를 확인해서 코드에 적용시켜보자

import styled from "@emotion/styled";

const Wrapper = styled.div`
  width: 1000px;
  height: 1000px;
  background-color: red;

  @media (min-width: 768px) and (max-width: 1199px) {
    width: 500px;
    height: 500px;
    background-color: green;
  }
  @media (max-width: 767px) {
    width: 100px;
    height: 100px;
    background-color: blue;
  }
`;
export default function ResponsiveDesignPage() {
  return <Wrapper>상자</Wrapper>;
}

그럼 크기에 맞게 상자의 색깔이 변하고 있음을 볼 수 있다(설정한대로)

근데 이렇게 픽셀을 지정하기보단
미디어 쿼리와 %를 이용해서 반응형디자인을 만들게된다

  1. mobile-first
  • 인스타그램을 생각해보면 모바일 먼저 만들고(웹없었음) 이후 이걸 웹으로 자연스럽게 늘리는 방식
    핸드폰으로 사용되는 서비스는 이런 방식을 하는게 더 좋다.
  1. web-first
  • 반대로 웹페이지 만들고 모바일사이즈로 줄여야되면 그걸 맞게 줄이는 것
    모바일로 줄일 때 핵심서비스를 빼고 필요없는건 가리거나 웹으로 가게 만들어서 보이는 것
    (아마 네이버를 예시로 들 수 있겠다)

그래서 디자인 할때 이런 방식에 유의해야한다.

모바일에서 그럼 가리고 싶다면? display: none;을 적용시키면 가릴 수 있다.

이런 거는 디자이너와 협업할 때 어려울 수 있다.
리스트를 크기를 줄일껀지, 내릴껀지, 이런건 기획자의 의도를 알아야한다(사전에 이야기가되어야함)
++ 반응형에 관한 디자인도 필요함

오늘의 요약

메모이제이션 + 반응형디자인

메모이제익션은 스테이트가 바뀌면 다시만들어진다고 했는데 어떤상황인지 다시 봄, 효율성을 위해 usecallback, usememo,를 사용함
근데 그 안의 state도 저장하기 때문에 prev를 사용해서 저장해야함
만약에 다시만들어야하면 dependency array에 넣어야함
+라이브러리도 다시 쓸 수 있음

Wappalyzer로 어떤 기술들을 썼는지 볼 수 있었음
반응형, 적응형이 있는데 반응형이 대세긴 하나 무조건 정답은 아님
그래도 트렌드에 맞춰서 할 수 있는 기술을 연습하는 것은 좋은거임

반응형은 자동이 아니고 하나하나 다 만들어줘야함

  • 우리가 이런 방식을 알고 협업할때도 알려줘야 트러블+노가다 스트레스가 적다.
profile
개발자 새싹🌱 The only constant is change.

0개의 댓글