[react] useEffect / useMemo / useCallBack / React.memo

eunbi·2020년 5월 3일
4

React

목록 보기
12/22

useEffect

  • 두 번째 인수 배열에 넣은 값들이 바뀔 때 useEffect가 실행된다.
useEffect(() => { //componentDidMount, componentDidUpdate역할
	interval.current = setInterbal(changeHand, 100)
    
    return () => { // componentWillUnmount 역할
    	clearInterval(interval.current)
    }
}, [imgCoord]) //이 값이 바뀔때 useEffect가 실행 (deps라고 한다)

deps에 값이 없는 경우

  • 어떤 값이 바뀌든 useEffect는 한번만 실행하고 종료한다는 의미 (componentDidMount와 같다)
  • 컴포넌트가 처음 렌더링 되고 난 후 한번만 실행된다.
  • return문 안에 함수는 컴포넌트가 사라질 때 한번만 실행된다.

deps에 값이 있는 경우

  • 처음 컴포넌트가 렌더링 되고 난 후, deps에 값이 바뀔 때마다 실행된다. (componentDidMount, componentDidUpdate역할)

  • return문에 실행 시점은 deps안에 값이 바뀌기 전에 실행된다.
    또한 컴포넌트가 사라질 때 실행된다.

  • interval, timeout 사용 시 항상 clear Interval, timeout을 return 안에서 해줘야한다.

  • props의 값이나 state값을 사용하고 있다면 항상 deps안에 넣어주어야한다.

  • deps안에 실행 조건을 넣어줄 수 있다

예 )

useEffect(() => {}, [balls.length === 0]) 
//balls.length === 0일때만 실행

또는 바뀌는 시점을 넣어준다


useEffect(() => {}, [timeouts.current]) 
// timeouts가 바뀔때마다 실행

주의할 점
배열의 요소로 넣어주는 것은 바뀌는게 아니다
예) array[i] = 값
-> 배열의 요소로 값을 넣어주는 것이기 때문에 바뀌는 것이 아니다
arrya = []
-> 배열을 넣어주는 것이기 때문에 바뀌는 것이다.(react가 감지함)

deps를 생략하는 경우

  • 컴포넌트 전체에서 useEffect가 실행된다.(어떤 동작을 하던지 전부 실행됨)

  • 부모 컴포넌트가 실행되면 자식 컴포넌트도 실행되기 때문이다.

  • 가상 DOM에서만 변경이 일어나고 실제 DOM은 바뀐 부분만 변경이 일어난다.

  • useEffect안에서 비동기 처리는 함수로 따로 분리하자

useEffect의 사용 예

Mount

  1. props의 값을 state로 저장할 때
  2. REAT API요청할 때
  3. 라이브러리 사용할 때
  4. setInterval, setTimeout

Unmount

  1. clearInterval, clearTimeout
  2. 라이브러리 인스턴스 제거

useLayoutEffect

화면 크기 늘렸다 줄였다 (화면 resizing) 하기 전에 발생
화면 layout변화를 감지할 때

useEffect : 화면이 완전히 바뀌고 난 후 발생

useLayoutEffect: 화면 바뀌기 전 발생(화면바뀌는 것을 감지)

useMemo

  • 배열(deps)안에 값이 바뀌기 전까지는 값을 기억하고 있는다.
  • 복잡한 함수 결과값을(리턴값) 기억 (ref는 일반 값을 기억)

useCallBack

  • 함수 자체를 기억

  • 렌더링 될 때 함수 자체가 재시작 돼도 함수가 새로 만들어지지 않는다.

  • 자식 컴포넌트에게 메서드를 전달할 때에는 useCallBack으로 감싸서 전달할 때마다 메서드가 새로 생성되지 않도록 한다.

  • 이전 state 값을 계속 기억하기 있기 때문에 함수 안에서 사용하는 state 혹은 props 가 있다면 꼭, deps 배열안에 포함시켜야 된다.

  • 컴포넌트에서 props 가 바뀌지 않았으면 Virtual DOM 에 새로 렌더링하는 것 조차 하지 않고 컴포넌트의 결과물을 재사용 하는 최적화 작업을 할 때, 이 작업을 하려면 함수를 재사용하는것이 필수다.

React.memo

  • 컴포넌트의 리렌더링을 최적화해준다. (props가 바뀌지 않으면 리렌더링이 일어나지 않는다.)

문제

함수를 useCallBack으로 감싸준다 하더라도 deps에 state값이 있다면 값이 바뀔때마다 함수가 새로 만들어진다. 때문에 하위 컴포넌트의 전체가리렌더링이 일어난다. (예 : userList에서 list를 새로 등록시, 기존 list도 전부 다시 렌더링이 된다.)

해결 방법은?

deps 에서 참조하고 있던 상태값을 지우고, 함수들에서 현재 useState 로 관리하는 상태값을 참조하지 않게 한다. 즉 함수형 업데이트를 한다.

setState의 콜백함수의 파라미터에서 최신 상태값을 참조 할 수 있기 때문에 deps 에 상태값을 넣지 않아도 된다.

예 : setUsers(prevUsers => prevUsers.concat(user))

propsAreEqual

React.memo 에서 두번째 파라미터에 propsAreEqual 이라는 함수를 사용하여 특정 값들만 비교를 하는 것도 가능하다.

export default React.memo(
  UserList,
  (prevProps, nextProps) => prevProps.users === nextProps.users
);

하지만 함수형 업데이트로 전환을 안했는데 이렇게 users 만 비교를 하게 된다면, 나머지 props에서 최신 상태값을 참조하지 않으므로 심각한 오류가 발생 할 수도 있다.

참고 : https://react.vlpt.us/basic/19-React.memo.html

profile
프론트엔드 개발자입니다 :)

0개의 댓글