TIL | react (useMemo, Virtual DOM, Redux ...)

·2023년 6월 26일

TIL # WIL

목록 보기
14/65

23.06.21

1. Hook

1-1. React.memo

React.memo : 컴포넌트를 메모리에 저장해두고 필요할 때 갖다 씀

리렌더링의 발생 조건은 ? state가 바뀌거나 / 내려받은 props가 변경되거나 / 부모 컴포넌트가 리렌더링 될 때 자식에서

근데 리렌더링은 최소로 일어나는게 좋음, 특히 부모에서 일어나도 자식에서 일어나지 않게 할 수 있음 !

=> 즉, 최적화 작업이 필요함

그렇다면 최적화는 어떻게 할까 ?

  1. memo(React.memo) : 컴포넌트를 캐싱 ‘메모이제이션’
  2. useCallback : 함수를 캐싱
  3. useMemo : (return) 값을 캐싱

1-2. useCallback

useCallback : 인자로 들어오는 함수 자체를 기억(메모이제이션)함

자식 컴포넌트에서 부모 컴포넌트에 있는 함수를 호출 시 자식 컴포넌트에 메모이제이션 되어있음에도 리렌더링됨. 왜냐하면 함수를 호출할 때 props로 새로운 값을 전달 받았다고 여겨졌기 때문임. 그러나 사실 함수 호출 시에 새로운 값을 받은게 없음
=> 여기서 함수는 (불변성이 없는데 ?????) 호출 시에 새로운 주소를 return 해주기에 props가 바뀐 줄 알고 리렌더링 되는 것임 !

그렇다면 여기서 불변성이란 ?
값이나 상태를 변경할 수 없는 것 => 메모리 영역에서 값이 변하지 않는다 !!!
(spread operator, map, filter, slice, reduce 등등 새로운 배열을 반환하는 메소드들을 활용해서 불변성을 지켜주면 됨)

즉, useCallback을 사용하여 함수를 ‘별도 메모리 공간에 저장’해두고 특정 조건이 아닌 경우에는 변경되지 않도록 막을 수 있음 => 그렇게 되면 최초의 주소 값만 내려오기에 리렌더링 되지 않는다 !
+의존성 배열 필요

1-3. useMemo

useMemo

const me = useMemo(() => {
    return {
      name: "Ted Chang",
      age: 21,
      isAlive: isAlive ? "생존" : "사망",
    };
  }, [isAlive]);

  useEffect(() => {
    console.log("생존여부가 바뀔 때만 호출해주세요!");
  }, [me]);

useEffect를 사용해서 해당 객체의 변화가 있을 때만 리렌더링 되게 해놨는데 그럼에도 불구하고 다른 함수를 호출하니 전체 컴포넌트가 리렌더링 됨

=> 그 해당 객체가 새로운 주소 값을 가져와 me라는 객체가 달라졌다고 인식하기 때문임
=> 즉, 우리는 me라는 객체가 변경되지 않았음을 알려주기 위해 useMemo를 사용해야 함
=> useMemo를 사용하므로써 아무리 호출해도 그 초기에 저장해놨던 me라는 객체의 메모리 주소 값을 불러오므로 리렌더링 되지 않음 !

📌
react에서 state(원시변수든 객체든 함수든)는 불변성(= 메모리 영역에서 값이 변하지 않는다)을 유지해야 하므로 react에서 state를 변경할 때 이전 상태를 직접 수정하는 것이 아니라 새로운 상태를 만들어야함.

새로운 상태를 만들기 위해 새로운 객체가 생성되었으며, 객체의 주소가 달라지는데 이는 이전 객체와는 다른 메모리 공간을 차지하고 있다는 것을 의미함. 이는 불변성을 유지하면서 상태를 변경하는 방법 중 하나

근데 이때 useEffect를 사용하면 의존성 배열을 통해 특정 값의 변화가 감지되면 내부 로직이 호출됨. 근데 이때 의존성 배열에 지정된 값이 객체라면 함수 호출 때마다 주소가 달라지므로 useEffect가 실행되고, 이는 상태 변경을 의미 !

즉, 이때 이러한 것을 막아주기 위해 useMemo를 사용해서 return으로 객체 초기 값(주소까지)을 저장해두고 그것을 실행시키면 리렌더링을 막아줌 !!!
📌


2. 라이프사이클

리액트 컴포넌트는 각각 [Mount] → [Update] → [Unmount]의 과정

...


3. DOM과 Virtual DOM

DOM(Document Object Model)은 Document Object를 홍보, 표현하기 위한 수단

  • 컴포넌트로 이루어진 페이지 = 문서
  • 페이지 안에 컴포넌트 하나하나 = 엘리먼트
  • DOM은 이 엘리먼트를 트리 형태로 표현한 것 = DOM TREE

그리고 트리의 요소 (= 엘리먼트 ?) 하나하나를 ‘노드’라고 하고 각각의 노드는 해당 노드에 접근(ex. getElementById, querySelector)과 제어(ex. innerHTML)를 할 수 있는 API를 제공

그렇다면 여기서 API란 ? 단순히 HTML 요소에 접근해서 수정할 수 있는 함수 ….

가상DOM은 실제DOM의 완벽한 복사본으로 객체 형태로 메모리에 저장되어 있음 => 그래서 더 빠르게 조작할 수 있고 작업이 더 가벼움

화면이 바뀌어야 함 = 렌더링 되어야 함 = 엘리먼트 DOM 요소가 갱신(=업데이트)되어야 함 = DOM 조작을 해야 함

가상DOM 과정

  1. 2가지 버전의 가상DOM이 필요
  2. diffing : 이 2가지 버전을 비교하여 어느 부분에서 변화가 있는지 파악
  3. reconciliation : 파악이 끝나면 변화가 있는 부분들을 모두 모아 한 번에 한 번만 적용 시킴 (배치 업데이트) => painting 작업이 제일 오래걸리기에 한 번에 모아 한 번만 작업하므로써 시간을 단축시키는 것 !

4. Redux 🔆

Redux : 상태관리를 도와주는 패키지(= 라이브러리), 전역 상태관리 라이브러리

리덕스와 같은 기능을 하는 다른 패키지들 -> MobX, Overmind.js, Recoil

리덕스를 사용하게 되면 state를 공유하고자 할때 부-자 관계가 아니여도 되고 중간 컴포넌트를 거치지 않아도 ‘중앙 state 관리소’ (= 전역상태, Global state) 느낌으로 state들을 접근과 제어로 관리해줌

// 앞에 + 붙으면 자동으로 숫자형으로 형변환 해줌
setNumber(+event.target.value);

...

0개의 댓글