Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

개발 기록

useEffect 본문

웹 자료/React

useEffect

기록개발자 2021. 5. 17. 15:38

React 라이브러리를 공부하면서 Hook 이란 개념을 자연스럽게 알게되었다.

이번 글에서는 React 기본제공 함수와 Hook의 차이에 대해 알아본다.

React 공식 문서를 따라 각색을 더해 따라 적어보며 개념 정리해보았다.

 

useEffect

 

useEffect 란?

useEffect는 어떤 Effect를 발생시키고 싶을 때 사용한다.
useEffect는 렌더링 결과가 실제 돔에 반영된 뒤에 호출된다.

 

useEffect의 지연타이밍
리액트 공식문서 : timing of effect 글
componentDidMount와 componentDidUpdate와는 다르게, useEffect로 전달된 함수는 지연 이벤트 동안에 레이아웃 배치와 그리기를 완료한 후 발생합니다. 그렇지만, 모든 effect가 지연될 수는 없습니다. 예를 들어 사용자에게 노출되는 DOM 변경은 사용자가 노출된 내용의 불일치를 경험하지 않도록 다음 화면을 다 그리기 이전에 동기화 되어야 합니다. useEffect는 브라우저 화면이 다 그려질 때까지 지연됩니다만, 다음 어떤 새로운 렌더링이 발생하기 이전에 발생하는 것도 보장합니다. React는 새로운 갱신을 시작하기 전에 이전 렌더링을 항상 완료하게 됩니다. ... 생략 ...


useEffect를 컴포넌트 안에서 불러내는 이유 

useEffect는 함수형 컴포넌트에서 사용되고 내부에 선언되게 된다.

useEffect를 컴포넌트 내부에 둠으로써의 이점은 effect(명령형함수 또는 타이머, 로깅, 변형, sideEffect등 을 발생시키는 함수)를 통해 const state 변수에 바로 접근할 수 있게 된다.
또한 함수의 범위 안에 있기 때문에 다른 API 없이도 값을 얻을 수 있다. 

Hook JS의 클로저를 이용해 JS가 이미 가진 방법을 사용할 수 있다.

 


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

그렇다. 기본적으로 첫번째 렌더링과 이후의 모든 업데이트에서 수행되고 리액트는 effect가 수행되는

 시점에 이미 DOM이 업데이트되었음을 보장한다.

 

 

 

정리를 이용하지 않는 side effect

//Class를 사용한 effect 처리

class Example extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count:0
        };
    }

    componentDidMount {
        document.title = `You clicked ${this.state.count} times`;
    }

    componentDidUpdate {
        document.title = `You clicked ${this.state.count} times`;
    }

    render() {
        return (
            <div>
                <p>You clicked {this.state.count} times</p>
                <button onClick={() => this.setState({ count:this.state.count + 1 })}>
                    Click Me
                </button>
            </div>
        );
    }
}

위 코드에서 class 안의 두 개의 생명주기 메서드에 같은 코드가 중복되는 것에 주의해야한다.

위의 컴포넌트에 필요로 하는 기능에서는 마운트된 단계이던가 업데이트되던가하는 생명주기에 관계없이 같은 side effect를 수행해야 하고 개념적으로는 렌더링 이후에는 항상 같은 코드가 수행되는 것이다. 그런데 리액트 클래스 컴포넌트에는 해당 메서드가 존재하지 않는다.

 

//Hook을 사용한 effect 처리

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

const Example = () => {
    const [count, setCount] = useState(0);

    useEffect(() => {
        document.title = `You clicked ${count} times`;
    });

    return(
        <div>
            <p>You clicked ${count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

 

위의 "Class를 사용한 effect 처리"의 코드와 같은 기능을 하는 코드다. 그리고 useEffect Hook에 함수를 전달하고 있는데 이 함수가 바로 effect다.

effect는 Example이라는 count 변수와 같은 함수내에 존재함으로  최신의 count 얻을 수 있다. 렌더링 시에 effect를 기억했다. DOM 업데이트 후 실행한다. 또한 이후 모든 렌더링에 똑같이 적용된다.

effect에서 중요한 점은 useEffect에 전달된 함수가 매 렌더링에서 다르다는 것이다. 즉 count 값이 제대로 업데이트되는지를 확신 할 수 있는 점이기도 하다.

 

정리를 이용하는 side effect(메모리 누수가 발생하지 않도록 정리하는 것은 매우 중요)

//Class를 사용하는 effect 처리
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';
  }
}
//Hook을 사용하는 effect 예시
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에서 함수를 반환하는 이유는 무엇일까? 

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

 

리액트가 effect를 정리(clean-up)하는 시점은 정확히 언제일까요? 

리액트는 컴포넌트가 마운트 해제되는 때에 정리(clean-up)를 실행한다. 하지만 위의 예시에서 보았듯이 effect는 한번이 아니라 렌더링이 실행되는 때마다 실행된다.

리액트가 다음 차례의 effect를 실행하기 전에 이전의 렌더링에서 파생된 effect 또한 정리하는 이유가 바로 여기에 있다.

 

세줄 정리

- useEffect는 리액트에게 컴포넌트가 렌더링 이후에 무엇을 해야하는 지 선언하고 알려주는 역할
- useEffect 함수는 렌더링 이후에 매번 수행된다.
- useEffect 사용 시 열고 닫기를 잘해야 메모리 누수가 적음을 인지하자.

 

 

참고

https://ko.reactjs.org/docs/hooks-effect.html

 

Using the Effect Hook – React

A JavaScript library for building user interfaces

ko.reactjs.org

https://velog.io/@kwonh/ReactHook-useState-%EC%99%80-useEffect-%EB%A1%9C-%EC%83%81%ED%83%AF%EA%B0%92%EA%B3%BC-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

[ReactHook] useState() 와 useEffect() 로 상탯값과 생명주기 사용하기

안녕하세요!리액트 훅에 대한 포스팅입니다!훅은 리액트 버전 ^16.8부터 사용할 수 있는데요리액트 문서에서는 훅을"함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 연동, 연결 (ho

velog.io

 

'웹 자료 > React' 카테고리의 다른 글

Mutiple await에 대한 이해  (0) 2021.05.24