실제로 hook을 구현하며, hook이 어떻게 작동하는지 확인해보려 한다. + js에 대한 이해도를 높인다.
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);
만약 위 클로저를 반복해서 호출한다면, 매번 함수는 호출되면서 state와 setState 함수를 반환하고 데이터 영역 어딘가에 새로운 _value의 공간을 만들어둘 것이다. 그리고 매번 state와 setState의 내부에 있는 _value는 그때마다 생성된 _value를 가리킬 것이다.
이로써 우리는 크로저를 사용해 useState()를 만들어냈다.
간단한 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);
App.click();
var App = React.render(Component);
const React = (function(){
//...내용 생략
})();
여기까지는 좋았다.
근데 여기서 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 뜸. => 위에서 내가 설명해두고 깜빡함. 싱글톤이었다는 사실을.
이유는 다음 편에서 계속.....