React Hook - useEffect 21.05.13


useEffect : component 렌더링 이후 useEffect 내부 코드 실행 + 함수 컴포넌트에서 *side effect를 수행 가능하다.

*Side Effect : 함수(또는 컴포넌트)의 입력 외에도 함수의 결과에 영향을 미치는 요인.

class를 사용하여 side-effect를 처리하려면 life cycle method(componentDidMount, componentDidUpdate, componentWillUnmount)를 사용해야하지만 Hook의 useEffect를 사용한다면 더 코드를 간결하고 직관적으로 구현할 수 있다.

  • syntax

useEffect(함수 실행 코드)

[리액트 컴포넌트 side effect 종류]

리액트가 DOM을 업데이트(렌더링)한 뒤 추가로 코드를 실행해야 하는 경우가 있다.

리액트 컴포넌트에는 일반적으로 clean-up이 필요한 side effect와 필요하지 않은 side effect로 구분할 수 있다.

clean-up을 이용하지 않는 side effect

네트워크 리퀘스트, DOM 수동 조작, 로깅 등은 clean-up(정리)이 필요 없는 side effect들이다.

  • class component를 이용한 side effect 처리
class Ex extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }

    // 컴포넌트 처음 실행 직후 실행
    componentDidMount() {
        // 중복 코드 발생
        document.title = `You clicked ${this.state.count} times`;
    }
    // state 업데이트 직후 실행
    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>
        )
    }
}
  • Hook useEffect를 활용하여 side-effect 처리
import React, { useState, useEffect } from 'react';

function Ex() {
    const [count, setCount] = useEffect(0);

    // 기본적으로 첫번째 렌더링과 이후의 모든 업데이트에서 수행
    // 즉, 첫 렌더링 직후 실행 + state가 갱신 될 때 마다 실행
    useEffect(() => {
        // 이 부분이 (side) effect
        // component 내부에 있기 때문에 state에 바로 접근 가능
        document.title = `You clicked ${count} times`
    });

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick = {() => setCount(count + 1)})> Click Me!!! </button>
        </div>
    );
}
clean-up을 이용하는 side effect

clean-up(정리)이 필요한 side effect도 있다. (ex : 구독 설정) clean-up을 하는 이유는 메모리 누수가 발생하지 않도록 하기 위함이다.

  • class compnent를 이용하여 clean-up이 필요한 side effect 처리 : componentWillUnmount
class FriendStatus extends React.Component {
    constructror(props) {
        super(props);
        // 현재 접속 여부를 구분하는 state
        this.state = { isOnline: null }

        // bind 사용 이유 : class기 때문에 this가 가리키는 인스턴스를 고정(묶어주기)
        // 호출되는 메소드(handleStatusChange)가 다른 곳에서 호출이 되기 때문에 this를 고정시켜줘야한다.
        // class 내에서는 bind this를 해주지 않으면 this가 undefined
        this.handleStatusChange = this.handleStatusChange.bind(this);
    }

    // component 첫 렌더링 직후 실행
    componentDidMount() {
        ChatAPI.subscribeToFriendStatus(
            this.props.friend.id,
            this.handleStatusChange
        );
    }

    // component 해제 시 실행
    // 컴포넌트가 소멸된 시점에(DOM에서 삭제된 후 === 렌더링에서 삭제 된 후) 실행 
    // 컴포넌트 내부에서 타이머나 비동기 API를 사용하고 있을 때, 이를 제거하기에 유용
    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';
    }
}
  • Hooks useEffect를 사용하여 clean-up이 필요한 side effect 처리 : useEffect return
class FriendStatus extends React.Component {
    constructror(props) {
        super(props);
        // 현재 접속 여부를 구분하는 state
        this.state = { isOnline: null }

        // bind 사용 이유 : class기 때문에 this가 가리키는 인스턴스를 고정(묶어주기)
        // 호출되는 메소드(handleStatusChange)가 다른 곳에서 호출이 되기 때문에 this를 고정시켜줘야한다.
        // class 내에서는 bind this를 해주지 않으면 this가 undefined
        this.handleStatusChange = this.handleStatusChange.bind(this);
    }

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

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

    componentDidMount() {
        ChatAPI.subscribeToFriendStatus(
            this.props.friend.id,
            this.handleStatusChange
        );
    }

    componentWillUnmount() {
        ChatAPI.unsubscribeFromFriendStatus(
            this.props.friend.id,
            this.handleStatusChange
        );
    }

    useEffect(ChatAPI.subscribeToFriendStatus(friend.id))
}






© 2020.11. by creamer

Powered by CREAMer