React Hooks useEffect

BBAKJUN·2022년 4월 18일
0

React

목록 보기
6/7
post-thumbnail

class형 컴포넌트로
AppHeader를 제작도중 리액트 lifeCycle을 잘몰라 hooks로 변경했던 기억이 났다.

당시 코드는 아래와 같았었다.

방금 리액트 라이프사이클 글을 작성해나가며 나의 무지함을 알았기에 이 글을 작성한다.

당연하게도 저코드는 내가 원하는

  • Route.pathname === router.pathname의 조건을 만족할때 pageHeader의 값을 변경시켜준다

이부분을 실행하지 못할것이다.

컴포넌트가 마운트될때에만 실행하는 componentDidMount 메서드를 사용했기 때문인데
내가 원하는대로라면 componentDidMountcomponentDidUpdate 에서 두번 실행시켰어야할것이다.

공식문서에도 매우 잘나와있는데 멍청했다..

나의 상황과 그냥 똑같은 상황이었던것이다 ㅋㅋㅋㅋ

컴포넌트가 방금 마운트된 상황인지 아니면 업데이트되는 것인지에 상관없이 동일한 side Effect를 수행해야 하기때문인데,
React class 컴포넌트는 그러한 메서드를 가지고 있지않았던 것이다.

Hooks useEffect

Hooks를 이용할때는 useEffect를 사용해주면 된다

useEffect가 하는 일은 무엇인가

useEffect Hook을 이용하여 우린 React에게 컴포넌트가 렌더링 이후에 어떠한 일을 수행해야하는지를 말한다.
React는 우리가 넘긴 함수를 기억했다가 DOM 업데이트를 수행한 이후에 불러낼것이다.

useEffect를 컴포넌트 내부에서 호출하는 이유는 무엇인가

useEffect를 컴포넌트 내부에 둠으로써 effect를 통해 state변수 (혹은 그 어떤 prop)에 접근할수있게 된다. 함수 범위 안에 존재하기에 특별한 API없이도 값을 얻을 수 있는 것

Hook은 자바스크립트의 클로저를 이용해 React에 한정된 API를 고안하는것보다 자바스크립트가 이미 가지고 있는 방법을 이용하여 문제를 해결한다.

useEffect는 렌더링 이후에 매번 수행 되는것인가

기본적으로 첫 렌더링과 이후의 모든 업데이트에서 수행된다.

clean-up을 사용하는 effects

지금까지는 정리가 필요하지 않은 side-effects를 보았지만
정리가 필요한 effects도 있다.

외부 데이터에 구독을 설정해야하는 경우를 생각해보자. 이런 경우 메모리 누수가 발생하지 않도록 정리하는것이 매우중요하다.

Class Clean-up

class에서는 componentDidMount에서 구독을 설정한뒤 componentWillUnmount에서 이를 정리한다.

class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

  render() {
    if (this.state.isOnline === null) {
      return 'Loading...';
    }
    return this.state.isOnline ? 'Online' : 'Offline';
  }
}

componentDidMountcomponentWillUnmount가 어떻게 대칭을 이루고 있는지를 보자.
두개의 메서드 내에 개념상 같은 effect에 대한 코드가 있음에도 불구하고 생명주기는 이를 분리하게 만든다.

Hooks Clean-up

정리의 실행을 위해 별개의 effect가 필요하다고 생각할수있다. 하지만 구독의 추가와 제거를 위한 코드는 결합도가 높기 때문에, useEffect는 이를 함께 다루도록 설계되었다.
effect가 함수를 반환하면 React는 그 함수를 정리가 필요한 때에 실행시킬 것이다.

import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // effect 이후에 어떻게 정리(clean-up)할 것인지 표시합니다.
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

effect에서 함수를 반환하는 이유는 무엇인가

추가적인 정리(clean-up) 메커니즘이다.
모든 effect는 정리를 위한 함수를 반환할수 있다. 이점이 구독의 추가와 제거를 위한 로직을 가까이 묶어둘수있게한다.
구독의 추가와 제거가 모두 하나의 effect를 구성하는 것이다.

React가 effect를 정리하는 시점은 언제인가

컴포넌트가 마운트 해제되는 때에 정리를 실행한다.
하지만 위의 예시에서 봤듯이 effect는 한번이 아니라 렌더링이 실행 되는 때마다 실행된다.
다음 차례의 effect를 실행하기 전에 이전의 렌더링에서 파생된 effect 또한 정리하는 이유가 바로 이때문이다.

return function 으로 꼭 named function을 반환해야하는것은 아니다. arrow function을 반환해도된다.

profile
함께 일하고 싶은 환경을 만들어가는 프론트엔드 개발자 박준형입니다.

0개의 댓글