"hook만들기 3탄"

최기환·2020년 3월 11일
0

Coding

목록 보기
4/4

5. useEffect를 만들어보자!


자 이제 hook 뉴비에게는 끝판왕이라 할 수 있는 useEffect를 만들어보자.

먼저, 만들어보기 전에 useEffect()는 이렇다.

useEffect(() => {
console.log('마운트 될 때만 실행됩니다.');
}, []);

이렇게 생겼다. useEffect는 첫 번째 인자로 콜백함수를 두 번째 인자로 배열을 넘겨주는 것 같다. 이제 추가해보자.

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 useEffect(callBack,dependecyArray) {
        const oldDepenpendcy = hooks[idx];
        let hasChanged = true;
        if (oldDepenpendcy){
            hasChanged = dependecyArray.some(
                (dependency, index) => !Object.is(dependency, oldDepenpendcy[index])
            );
        }
        if(hasChanged) callBack();
        hooks[idx] = dependecyArray;
        idx ++;
    }
    
    function render(Component){
        idx = 0;
        const C = Component(); 
        C.render();

        return C;
    }

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

function Component() {
    const [count,setCount] = React.useState(1);
    const [text, setText] = React.useState('apple'); 
    React.useEffect(() => {
        console.log('유즈이펙트다!')
    },[])
    return {
        render: () => console.log(count, text),
        click: () => setCount(count+1),
        type: word => setText(word), 
    };
}

var App = React.render(Component);
App.click();
var App = React.render(Component);
App.type('peer');
var App = React.render(Component);

우선은 이렇게 만들 수 있다.
자 이제 전체 코드를 보면 복잡하니 useEffect 관련 코드만 뜯어보자.

const React = (function(){
    //...생략
    function useEffect(callBack,dependecyArray) {
        const oldDepenpendcy = hooks[idx];
        let hasChanged = true;
        if (oldDepenpendcy){
            hasChanged = dependecyArray.some(
                (dependency, index) => !Object.is(dependency, oldDepenpendcy[index])
            );
        }
        if(hasChanged) callBack();
        hooks[idx] = dependecyArray;
        idx ++;
    }
    //...생략
})();

function Component() {
    //...생략
    React.useEffect(() => {
        console.log('유즈이펙트다!')
    },[])
    //...생략
}

1. Component 안의 useEffect를 먼저 보자.

  1. 콜백함수와 빈 어레이를 전달했다.

2. useEffect의 로직을 간단하게 살펴보자.

  1. useEffect는 콜백함수와 dependencyArray를 넘겨받는다.
  2. dependencyArray를 useEffect(자신이)가 담당하는 훅 어레이에 넣어둔다.
  3. 화면이 렌더 될 때(useEffect를 다시 호출할 때), 새로 받은 dependencyArray와 기존에 훅에 넣어둔 어레이를 비교한다.
  4. 두 어레이를 비교해서 내용이 다르면 콜백함수를 작동한다.

3. 세부적으로 뜯어보자. (useEffect dependencyArray로 []를 넘겨줄 경우)

  1. useEffect는 hooks어레이에서 자신의 칸(index)을 할당받는다.
    => 위 예제의 경우 hooks[0] => count , hooks[1] => text, hooks[2] => useEffect
    => useEffect와 useState는 같은 hooks 어레이를 공유한다.
  2. 최초 렌더시, oldDependency에 hooks[자신의index]값을 넣는다.
    => 최초에는 당연히 undefined이다. 아직 hooks[자신의index]에 어떤 값도 넣지 않았기 때문이다.
  3. hasChanged에 먼저 true를 넣는다. (3번 과정을 위해)
  4. oldDependency가 undefined가 아닐 경우, if문을 실행한다.
    => if 문은 hasChanged가 필요한지 안한지 구분하기 위한 부분이다.
    => 랜더 될때 마다 새롭게 받은 dependencyArray와 기존에 hooks[자신의index]에 넣어둔 oldDependency를 비교한다.
    => 두 어레이의 내용이 다르면, 내가 감시하고 있는 값이 변했다는 것을 인지하고 hasChanged를 true로 그게 아니면 false를 할당한다.
  5. hasChanged가 true이면 콜백함수를 발동한다.
  6. hooks[자신의index]에는 dependencyArray를 새롭게 할당한다.
  7. 다음에 올 useState등 hooks의 공간을 사용할 새로운 녀석을 위해 idx++를 해준다.
    => []를 넘겨줄 경우에는 최초에만 발동한다. 왜? 이후에는 oldDependency와 dependencyArray를 비교해도 값이 같으니 hasChanged가 true이기에 콜백함수가 발동하지 않는다.

4. useEffect dependencyArray로 아무것도 안 넘겨줄 경우

  1. oldDependency와 dependencyArray가 계속해서 undefined이다.
  2. if문이 아예 작동하지 않는다.
  3. hasChanged는 계속 true다.
  4. 콜백함수는 렌더될 때마다 발동한다.

5. useEffect dependencyArray로 [count] 혹은 [count, text]와 같이 넘겨줄 경우

  1. 최초에는 일단 콜백함수를 작동한다.
  2. 콜백함수가 작동하고, hooks[자신의index]에 전달받은 dependencyArray를 할당한다.
  3. 렌더될 때마다. oldDependency(기존에 전달받은 값)과 dependencyArray(새롭게 전달받은 값)을 비교한다.
  4. 비교해서 두 값이 서로 다르면 콜백함수를 발동한다.
    => 내가 감시하고자 하는 값을 []안에 넣어서 전달해주면, 해당 값이 변화할 때마다 useEffect의 콜백함수가 발동한다.

hook 기초 박살내기 끝.

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

0개의 댓글

관련 채용 정보