티스토리 뷰

React Hooks란?

React v16.8에 추가된 새로운 기능이다.

기존 함수 컴포넌트에서는 Class컴포넌트의 life cycle기능을 사용할 수 없었는데 hooks를 이용하여 가능하도록 했다.

(class 컴포넌트는 hooks사용 불가능)

https://kmj24.tistory.com/118

 

[React] Lifecycle과 useEffect hook

React는 class로 컴포넌트를 생성할 수 있고, function으로 컴포넌트를 생성할 수 있다. class컴포넌트와 함수 컴포넌트의 차이는 Lifecycle method를 사용할 수 있냐 없냐가 있다. React에서 함수 컴포넌트를

kmj24.tistory.com

 

State Hook

class컴포넌트에서 state는 object 형태로 사용했지만 state hook은 object뿐만아니라 단일 데이터타입으로도 사용할 수 있다. state hook은 아래와 같은 형태로 사용할 수 있다.

const [statehook, setStatehook] = useState<string>("초기상태");
setStatehook("변경된상태");

 

 배열 구조분해 문법을 이용하여, 첫번째 원소는 현재의 상태를 저장하는 원소이고, 두번째 원소는 이 값을 업데이트하는 함수이다.

 useState는 컴포넌트가 렌더링 될 때 단 한번 생성된다.  

더보기

react 공식문서

 - createState가 아닌 useState로 이름을 지은 이유는 컴포넌트가 렌더링할 때 오직 한번만 생성되기 때문에 "Create"라는 이름이 정확하지 않을 수 있다. 컴포넌트가 다음 렌더링을 하는 동안 useState는 현재 state를 준다.

Effect Hook

useEffect는 class컴포넌트의 Life Cycle 기능을 사용할 수 있도록 해준다.

effect hook을 사용하여 함수 컴포넌트에서 side effect를 수행할 수 있다.

useEffect(() => {
  effect
    return () => {
  cleanup
  }
}, [input])

componentDidMount, componentDidUpdate, componentWillUnmount가 합쳐진것으로 생각하면 된다.

 react 컴포넌트에 일반적으로 정리(clean-up)가 필요한 것과 정리가 필요하지 않은 것인 두 종류의 side effects가 있다.

정리가 필요한 effect는 컴포넌트가 마운트 해제(componentWillUnmount)되는 시점에 정리를 한다.

 

Hooks의 규칙

오직 React 함수 내에서 Hook을 호출해야 한다.

 - 일반적인 Javascript함수에서 호출하면 안된다.

 - Costom Hook을 만들어 그 안에서 Hook을 호출하여 사용하는 방법이 있다.

반복문, 조건문, 중첩된 함수 내에서 Hook을 호출하면 안된다.

 - 조건 분기를 통해 useEffect의 렌더링 시점이 변경되기 때문에 버그가 발생할 수  있다.

React함수의 최상위 시점에 Hook을 호출해야 한다.

이러한 규칙을 따르면 컴포넌트가 렌더링될 때 마다 항상 동일한 순서로 Hook이 호출되는것이 보장된다.

ESLint 플러그인을 사용하여 이러한 규칙에 대한 확인을 할수 있다.

 

React Hook이 실제로 동작하는 원리

 React hook의 내부 동작에 대한 이해를 위해 javascript의 closure에 대하여 알고 있어야 한다.

https://kmj24.tistory.com/115

 

closer function

클로저는 function간 어휘적 환경의 조합이다. 클로저를 이해하기 위해 먼저 javascript가 어떻게 변수의 유효 범위를 지정(Lexical scoping)하는지에 대한 이해가 필요하다. Lexical Scoping(어휘적 범위 지정

kmj24.tistory.com

closure란 함수와 함수가 선언된 어휘적 환경의 조합이다.

함수가 속한 Rexical Scope를 기억하며 함수가 Rexical Scope밖에서 실행될 때 이 Scope에 접근할 수 있게 하는 기능을 의미한다.

 

간단하게 useState, useEffect hooks를 구현한 코드이다.

const React = (function() {
    let hooks: any = [];
    let currentHook: number = 0;

    function useState<T>(initVal: T): [T, (newVal: T) => void]{
        const state = hooks[currentHook] || initVal;
        const _currentHook = currentHook; //상태에 대한 배열의 index를 고정해둔다.
        const setState = (newVal: T) => {
            hooks[_currentHook] = newVal; //고정한 index에  값을 집어 넣는다.
        }
        currentHook++; //어떤 state가 설정 되었을때 다음 state가 설정될 경우를 위해 index를 1증가시켜 둔다.
        return [state, setState];
    }
    
    function useEffect(callback: Function, depArray?: any[]){
        //deps배열에 바뀐 내용이 있는지 검증
        const hasNoDeps: boolean = !depArray;
        const deps = hooks[currentHook];
        const hasChangedDeps: boolean = deps ? !depArray?.every((el: any, i: number) => el === deps[i]) : true;
        if(hasNoDeps || hasChangedDeps){
            //바뀐 내용이 있다면 첫번째 parameter로 받아온 callback함수를 실행한다.
            callback();
            hooks[currentHook] = depArray;
        }
        currentHook++;
    }

    function render(Component: Function) {
        currentHook = 0;
        const C = Component();
        //컴포넌트의 render함수(closure)를 실행하여 React 함수 전체를 업데이트한다.
        //useState로 설정해 둔 각각의 state별로 React App 전체를 업데이트 하여 상태가 연동되도록 한다.
        C.render();
        return C;
    }

    return {
        useState,
        useEffect,
        render
    };
})();

function Component(){
    const [count, setCount] = React.useState<number>(1);
    const [text, setText] = React.useState<string>("초기값");

    React.useEffect(() => {
        console.log(`increase count ${count}`);
        console.log(`텍스트 "${text}"`);
    }, [count, text]);

    return {
        render: () => {
            console.log("컴포넌트를 렌더링 합니다.")
        },
        click: () => setCount(count + 1),
        setString: (newVal: string) => setText(newVal) 
    }
}

export function run(){
    let App = React.render(Component);
    App.click();
    App.setString("바뀐값1");
    App = React.render(Component);
    App.click();
    App.setString("바뀐값2");
    App = React.render(Component);
    App.click();
    App.setString("바뀐값3");
    App = React.render(Component);
}

실행 결과

React함수 내에서 useState, useEffect라는 closure를 형성한다. 또한 useState내에서는 setState라는 closure를 형성하며,

render라는 closure 함수로 React함수 전체를 실행하는 느낌으로 상태를 업데이트 한다.

 

closure에 대한 개념만 공부했을때와는 다르게 실제로 react에서 사용되는 useState와 useEffect를 비슷하게 구현해봄으로써 closure에 대하여 다시한번 복습할 수 있는 좋은 기회가 되었다.

또한 react hooks의 구조를 공부하여 react app을 만들때 어떻게 만들어야 될지에 대한 이해가 조금 올라간 것 같다.

 

 

참고

https://hewonjeong.github.io/deep-dive-how-do-react-hooks-really-work-ko/

 

[번역] 심층 분석: React Hook은 실제로 어떻게 동작할까?

React Hook에 대해 이해하려면 JavsScript 클로저에 대해 잘 알아야합니다. React의 작은 복제본을 만들어보며 클로저와 hook의 동작 방식을 알아봅니다.

hewonjeong.github.io

https://rinae.dev/posts/getting-closure-on-react-hooks-summary

 

'Getting Closure on React Hooks' 정리

JSConf.Asia 2019에서 발표된 React Hooks를 직접 구현해보는 세션 정리

rinae.dev

 

'front-end > react' 카테고리의 다른 글

Next.js 맛보기  (0) 2021.08.02
[React-Redux] ducks pattern  (0) 2021.07.20
Redux-saga로 웹 소켓 통신 구현  (0) 2021.06.13
[React] react router  (0) 2021.06.04
Redux  (0) 2021.05.23
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
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
글 보관함