"hook만들기 2탄"

최기환·2020년 3월 11일
0

Coding

목록 보기
3/4

4. useState를 여러번 쓸 수 있게 만들어보자!


지난편 마지막 코드에서 주석과 같은 결과를 출력하는 이유는 아래와 같다.

이유: React는 싱글톤이자 클로저다. 때문에, setCount와 setText가 같은 value값을 가리키기 때문이다.
1. 최초 할당시에 _val은 비어있으므로, 각각 count와 text에 1과 'apple'이 할당됨.
2. click을 하면서, setCount는 _val에 2를 저장해버림. => 두 번째 호출 시에 2 2 를 출력함 : Component 안의 count와 text가 _val 하나를 공유해서 발생하는 문제
3. 2와 같은 이유로 peer peer을 출력

해결방법은?
_val을 어레이로 대체해서 값을 저장하고, 각 useState는 해당 값의 인덱스를 기억한다.

const React = (function(){ 
    let hooks = []; 
    let idx = 0;
    
    function useState(initVal){
        const _idx = idx;
        const state =  hooks[idx] || initVal; 

        const setState = newVal =>{
            hooks[_idx] = newVal; 
        };
        idx++;

        return [state,setState];
    }
    
    function render(Component){
        idx = 0;

        const C = Component(); 
        C.render();

        return C;
    }

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

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

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

var App = React.render(Component);// 1 'apple'
App.click();
var App = React.render(Component);// 2 'apple'
App.type('peer');
var App = React.render(Component);// 2 'peer'

해결 방법

let hooks = [];

_val 을 hooks 어레이로 대체했다. 이제 우리는 useState를 몇번을 사용하든 새로운 값들을 차곡차곡 저장할 수 있다.
2.

let idx = 0;

저장을 했으면 해당 데이터를 가지러 갈 수 있도록, index값도 챙겨두기 위해 idx를 만든다.
3.

const _idx = idx;

useState를 호출할 당시 React의 idx 값을 기억한다. => hooks에 저장해둔 자신의 값에 접근하기 위해.
4.

const state =  hooks[idx] || initVal;

최초에 useState()를 호출하면 hooks[idx]는 undefined이므로 initVal 값을 state에 담는다.
아직까지 hooks는 빈 어레이이다. 하지만 생성된 useState는 state를 통해 값을 저장하고 있으며, 나중에 사용될 _idx값도 가지고 있다.
5.

const setState = newVal =>{ 
    hooks[_idx] = newVal; 
};
idx++;

setCount라든가, setText함수가 호출될 경우, 즉 setState가 호출될 때, 그때 비로소 hooks 어레이의 자신의 칸에 값을 저장한다.
자신의 칸은 자신이 가지고 있는 idx를 통해 접근이 가능하다.
위 예제의 경우 count는 0번 text는 1번이다.
idx++는 윗 줄처럼, useState가 여러번 선언될 경우, 다음 녀석은 내 다음 번호를 가져가라고 ++해주는 것이다.
6.

function render(Component){
    idx = 0;
    //...생략
}

제일 중요한 놈이다.
React.render(Component) 를 호출할 때마다 idx는 0으로 다시 돌려둔다.
계속 증가하는 idx 때문에, state는 hooks 내부에 있는 자신의 것을 가리키지 못한다.
예를 들어
1. React.render(Component) 최초 호출
2. hooks는 빈 어레이, 각 클로저의 idx에는 0, 1 그리고 state에는 1, 'apple' 저장
=> 1, 'apple' 출력
3. App.click()호출
4. count 값인 1을 불러오고 여기에 1을 더한 값인 2를 hooks[0]에 저장 => hooks = [2]
5. React.render(Component)호출
6. idx 는 2,3 => hooks[2], hooks[3]은 없음 (현재 hooks는 4번 상태) => 위 2번 반복
7. render 시에 hooks[2], hooks[3]은 없으므로, 자신의 state 값 출력
=> 1, 'apple' 출력
이와 같은 방법으로 계속해서 콘솔창에 찍히는 값은 1 'apple' 이다.

다음 시간에는 이어서 useEffect를 만들어보자.

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

3개의 댓글

관련 채용 정보