Hook의 사용과 렌더링

조민성·2024년 10월 1일

React

목록 보기
4/9

1. Hook의 종류와 사용법

  • Hook: 여러 컴포넌트 중 function이 class를 사용할 수 있도록 도와주는 기능.

  • useEffect: useEffect(() ⇒ {함수}, [state or data값])의 형태로, 렌더링 때마다 특정한 작업을 하게 도와준다.

    useEffect((){함수})
    • =⇒ 페이지를 렌더링(mount)할 때마다 함수가 실행된다.

      useEffect((){함수}, [state or data값])
    • =⇒ 첫 렌더링 시에만 함수가 실행된다.

      useEffect((){함수}, [state or data값])
    • =⇒ 해당 state or data값이 변화할 때 함수가 실행된다.

  • useCallback: 기존의 연산 결과값을 다음 번에 재사용하기 위해 저장해두었다가 함수를 반환하는‘Memoization’의 기능을 구현함.

1.1. useEffect 사용예시

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

function Counter() {
    console.log('Render Counter')

    const [value, setValue] = useState(0);
    
    //useEffect 사용 1. body 클릭시 콘솔에 어떻게 뜨는지 보기
    useEffect(() => {
        console.log(
            '[Function] useEffect []: 컴포넌트가 마운트될 때 한 번만.'
        );
        const eventHandler = () =>{
            console.log('click body');
        };
        document.body.addEventListener(
            'click',
            eventHandler
        );
        return () => {
            console.log(
                '[Function] useEffect return []: 컴포넌트가 언마운트 될 때.'
            );
            document.body.removeEventListener(
                'click',
                eventHandler
            );
        };
    }, []);

    // useEffect 사용 2. 컴포넌트 마운트 시 value가 변경 or 새로 useEffect를 수행할 때.
    useEffect(() => {
        console.log(
            '[Function] useEffect [value]: 컴포넌트가 마운트될 때, + value가 변경되면, '
        );
            const eventHandler = () =>{
                console.log('click body');
            };
            document.body.addEventListener(
                'click',
                eventHandler
            );

        return () => {
            console.log(
                '[Function] useEffect return [value]: 새로 useEffect를 수행하기 전에,'
            );
        };
    },[value]);
    
    return(
        <div>
            <h1>value:{value}</h1>
            <button onClick={increaseValue}>Increase Value</button>
            <button onClick={resetValue}>reset Value</button>
        </div>
    )
}
export default Counter;

1.2. useCallback 사용예시

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

function Counter() {
    console.log('Render Counter')

    const [value, setValue] = useState(0);
    
// useCallback의 사용법. 이전에 있던 memoization된 값(여기서는 value)을 다음 렌더링에서 재활용하는 방식.
    const increaseValue = () => {
        setValue(value + 1);
        console.log('Render Counter2')
    };
    
    const resetValue = useCallback(() => {
        setValue(0);
    }, []);

    return(
        <div>
            <h1>value:{value}</h1>
            <button onClick={increaseValue}>Increase Value</button>
            <button onClick={resetValue}>reset Value</button>
        </div>
    )
}
export default Counter;

1.3. Hook 기능 사용 시 주의점

  1. 반복문 or 조건문 내부에서 Hook 구문이 실행될 수 없다.
  2. Hook 기능은 component 내부에서만 사용하자.

2. 렌더링

2.1. 렌더링의 과정

  1. Re-rendering이란? state나 props의 상태가 변화했을 때, 다시 렌더링하는 것.

2.2. Class Component와 Functional Component의 Life Cycle 비교

리액트 렌더링 과정_클래스 컴포넌트.png

  1. Class Component
  • Mounting: 가장 처음 Component가 실행되었을 때
  • Updating: Component의 상태가 변경되었을 때
  • UnMounting: Component를 지울 때

함수형 컴포넌트 라이프사이클.png

  1. Functional Component
  • 처음 mount되면, 자신을 바로 실행하고, 반환된 jsx값을 DOM에 반환함.
  • Update하는 경우에도 똑같이 실행하고 반환된 jsx값을 DOM에 반환함.
  • useEffect를 통해 Class Component의 componentDidMount, componentDidUpdate, componentWillUnmount 기능을 모두 수행할 수 있다.

2.3. 예시를 통한 렌더링의 비교

  1. Class Component
import {Component, useEffect, useState} from "react";

//Class Component의 lifecycle. 렌더링을 기반으로 다양한 method들이 실행된다.
class ClassComponent2 extends Component{
    state = {
        value: 0
    };

    constructor(props) {
        console.log('[Class] Constructor');
        super(props);
        this.state = {
            value: 0
        };
    }

    // 컴포넌트 렌더링 전 실행(return이 false면 렌더링 안함)
    shouldComponentUpdate(nextProps, nextState, nextContext) {
        console.log('[Class] shouldComponentUpdate');
        return true;
    }

    // 컴포넌트 마운트가 끝나면 실행
    componentDidMount() {
        console.log('[Class] componentDidMount');
    }

    // 컴포넌트 업데이트 후 실행
    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('[Class] componentDidUpdate');
    }

    // 컴포넌트 언마운트 직전 실행
    componentWillUnmount() {
        console.log('[Class] componentWillUnmount');
    }

    render() {
        console.log('[Class] render');
        return(
            <div>
                <h1>ClassComponent</h1>
                <h1>value: {this.state.value}</h1>
                <button
                    onClick={()=>{
                        this.setState((state)=> ({
                            value: state.value + 1
                        }));
                    }}
                >
                    Increase Value</button>
            </div>
        )
    }

}
export default ClassComponent2;
  1. Functional Component
import {useEffect, useState} from "react";

//Functional Component의 구현. useEffect를 사용하여 Mount/Update/UnMount가 모두 처리된다.
function FunctionalComponent() {
    console.log('[Function] Beggining');    //Mount 시 1번 로그, Update 시 1번 로그
    const [value, setValue] = useState(0);

    useEffect(() => {   //Mount될 때의 useEffect. //Mount 시 3번 로그, Update 시 생략.
        console.log('[Functional] useEffect []');
        return() => {   //Unmount 시 1번 로그.
            console.log(
                '[Function] useEffect return []'
            );
        }
    }, []);

    useEffect(() => {   //value가 update될 때, 위 useEffect는 생략하고 ReRendering된다. //Mount 시 4번 로그, Update 시 4번 로그.
        console.log('[Functional] useEffect [value]');
        return() => {
            console.log(
                '[Function] useEffect return [value]'
                   //Update 시 3번 로그, Unmount 시 2번 로그.
            );
        }
    }, [value]);

    console.log('[Function] end');  //Update상황에서 이 로그가 실행된 뒤 화면에 출력된다.
     //Mount 시 2번 로그, Update 시 2번 로그

    return(
        <div>
            <h1>FunctionComponent</h1>
            <h1>value: {value}</h1>
            <button
                onClick={()=>{
                    setValue((state)=>state + 1);   //value를 update시키는 trigger.
                }}
            >Increase Value</button>
        </div>
    )
}
export default FunctionalComponent;

3. 간단한 아코디언 컴포넌트 만들기

  • 조건: 오른쪽 상단의 ‘+’ 버튼을 누르면 하단 ‘content’ 페이지가 펼쳐지고, 다시 ‘-’ 버튼을 누르면 하단 ‘content’ 페이지가 접히게 만들어보자. ⇒ 버튼에 대해 변화를 주는 함수를 만들자!
    import {useEffect, useState} from "react";
    
    function Accordion({title, content}){
        const [isOpened, setIsOpened] = useState(false);
    
        return(
            <div>
                <div
                    style={{
                        background: '#666',
                        color: 'white',
                        fontWeight: 'bold',
                        padding: 10,
                        display: 'flex',
                        justifyContent: 'space-between'
                    }}
                >
                    <div>{title}</div>
                    <div
                        onClick={()=>{
                            // setIsOpened(!isOpened);  //1안. 직접 바꿔주기
                            setIsOpened((state)=>{
                                return !state   //2안. onClick 내부에서 자체적으로 바꾸기.
    
                            });
                        }}
                    >{isOpened ? '-' : '+'}</div>
                </div>
                {isOpened && <div style={{
                    border: '1px solid #999',
                    padding: 20
                }}
                >
                    {content}
                </div>}
    
            </div>
        )
    }
    
    export default Accordion;
profile
사람도 사랑도 계획적으로

0개의 댓글