"hook만들기 1탄"

최기환·2020년 3월 11일
1

Coding

목록 보기
2/4

1. 왜 만드는가?


실제로 hook을 구현하며, hook이 어떻게 작동하는지 확인해보려 한다. + js에 대한 이해도를 높인다.

2. useState


const [value, setValue] = useState(0);

이 문장의 의미는 이렇다. value에 0을 할당하고, setValue함수를 통해서만 value값을 바꿀 수 있다.

느낌상 객체지향언어의 class와 같은 느낌이 확 든다. useState()를 통해 인스턴스를 만드는데, 해당 인스턴스는 자신만의 상태를 가지고 있고, 그 상태는 자신이 제공하는 함수를 통해서만 조작이 가능하다. 다만, 클래스와는 느낌만 비슷하지 완전히 다르다. 위의 경우 setValue()를 통해서만 value값을 변경할 수 있기 때문이다. (물론 Java처럼 value값을 private으로 묶고 setValue()함수를 제공할 수 있겠다만,,,,)

그리고 js에는 class가 아닌 closure가 완벽하게 위와 같은 기능을 제공해줄 수 있다. 그렇게 구현해보면 아래와 같다.

const useState = (value) => {
    let _value = value;
    const state = _value;
    const setState = newVal => {
        _value = newVal;
    } 
    return [state, setState];
}

const [value, setValue] = useState(0);
console.log(value);
  1. useState라는 함수 안에 _value 변수, state 함수, setState 함수를 만든다.
  2. value에는 useState의 state 변수가, setValue에는 setState 함수가 할당된다.
  3. 최초 _value에 0을 할당한다.
  4. 데이터 영역 어딘가에 0이 저장되어 있고, useState 함수는 state,setState를 반환하고 사라진다. (일반 함수라면 여기서 끝)
  5. 클로저이기에, 함수는 사라지지만, value를 호출할 경우 반환되는 _value는 데이터 영역 어딘가에 있는 0을 가리키고, setValue 내의 _value도 마찬가지다.

만약 위 클로저를 반복해서 호출한다면, 매번 함수는 호출되면서 state와 setState 함수를 반환하고 데이터 영역 어딘가에 새로운 _value의 공간을 만들어둘 것이다. 그리고 매번 state와 setState의 내부에 있는 _value는 그때마다 생성된 _value를 가리킬 것이다.

이로써 우리는 크로저를 사용해 useState()를 만들어냈다.

3. React로 시험해보자


간단한 React 컴포넌트를 하나 만들고 시작하자.

const React = (function(){ //React 컴포넌트를 싱글톤으로 소환했다. 프로그램 전체에 이제 이 객체는 React 하나다. 
    let _val; // _val을 useState 함수에서 밖으로 빼냈다.
    
    function useState(initVal){
        const state =  _val || initVal; 
        // _val 값이 있으면 그 값을 state에 할당하고 아니면 initVal를 넣어라. 최초에만 initVal을 할당하겠지.
        const setState = newVal =>{
            _val = newVal;
        }

        return [state,setState];
    }
    
    function render(Component){
        const C = Component(); 
        // 
        C.render();

        return C;
    }

    return { useState, render };
})();//이로써 React는 싱글톤이 되는데 아래 5번 설명 참고.

function Component() {
    const [count,setCount] = React.useState(1);

    return {
        render: () => console.log(count),
        click: () => setCount(count+1),
    };
}

var App = React.render(Component);
App.click();

var App = React.render(Component);
var App = React.render(Component);

1.처음 호출될 때 진행 순서는 다음과 같다.

  1. React.render 함수에 Componet 함수를 전달한다.(js는 함수도 파라미터로 전달가능. 1급 객체이기에. )
  2. React의 render 함수가 호출된다
  3. Componet함수를 실행한다.
  4. Component 안에서 React의 useState 함수가 호출된다.
  5. count에 1(_val이 현재 undefined이므로 initVal 할당)을, setCount에 React의 _val에 접근(??복선)하는 함수를 리턴한다.
  6. C에는 Componet()가 할당되고, C.render() (Component 함수에서 리턴하는 render()함수)를 호출한다.
  7. 현재 React의 _val에 1이 저장되어 있는데, 이 값을 count가 가리키고 있고, 그 결과를 1을 출력한다.
  8. App에는 Component()를 할당했던 C를 반환한다.
App.click(); 

2.호출될 때 진행 순서다.

  1. count를 통해 React의 _val 값을 가져오고 그 값에 1을 더한다.
  2. setCount를 통해 React _val의 값에 위 값을 할당한다.
var App = React.render(Component);

3.한번 더 호출될 때는 다음과 같다.

  1. 1번에서 진행한 8단계의 할당과정을 반복한다.
  2. 1번 진행 과정 중 5번이 좀 다르다.
  3. 5번처럼 count에 1을 할당하지 않는다. 왜? _val 에 이미 2가 있기 때문이다.
  4. App에 새로 할당하는 것 같지만, React는 싱글톤이라는 점을 잊지 말아야한다.
  5. const state = _val || initVal; => _val이 있으면 _val을 할당한다.
  6. 결론 : 2를 출력함

4. ps: 테스트 돌릴 때, render 함수 내에서 const C = Component로 할당했더니, C.render()라는 함수는 없다고 에러를 뱉었다..

5. React가 싱글톤인 이유

const React = (function(){
    //...내용 생략
})();
  1. 맨 마지막에 ()를 통해 함수를 호출했다 => 즉시실행함수다.
  2. 익명 즉시실행함수의 결과를 React에 할당했다. ( return하는 값은 함수다. => 클로저 )
  3. var App = React, var App2 = React의 App과 App2 같은 객체를 가리킨다.
  4. React 변수는 즉시실행함수가 리턴한 함수를 담고 있고, 해당 함수들은 즉시실행함수가 실행될 때, 함수 내부에서 만들어진 변수들을 가리키고 있기 때문이다.
  5. 즉 React를 여러번 호출하더라도 최초에 만들어진 즉시실행함수의 리턴 함수를 담고 있으므로 매번 같은 내용을 가리키는 변수라는 것이다.

여기까지는 좋았다.
근데 여기서 useState를 하나 더 만들어주면 말썽이 난다.

const React = (function(){  
    let _val; 
    
    function useState(initVal){
        const state =  _val || initVal;
        const setState = newVal =>{
            _val = newVal;
        }

        return [state,setState];
    }
    
    function render(Component){
        const C = Component();
        C.render();

        return C;
    }

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

function Component() {
    const [count,setCount] = React.useState(1);
    const [text, setText] = React.useState('apple'); // useState를 추가해줬다.

    return {
        render: () => console.log(count, text),
        click: () => setCount(count+1),
        type: word => setText(word), // text를 바꿀 type 인터페이스를 추가해줬다.
    };
}

var App = React.render(Component);// 1 'apple' 을 출력함
App.click();
var App = React.render(Component);// 2 2를 출력함(...??)
App.type('peer');
var App = React.render(Component);// peer peer 을 출력함 (왜쥦??)
console.log(React._val)// 혹시? 하면서 궁금해서 해봄 => undefined 뜸. => 위에서 내가 설명해두고 깜빡함. 싱글톤이었다는 사실을.

이유는 다음 편에서 계속.....

참고영상 (https://www.youtube.com/watch?v=KJP1E-Y-xyo)

profile
개발자를 위한 개발자입니다.

0개의 댓글

관련 채용 정보