function useState(initialValue) {
var _val = initialValue;
function setState(newVal) {
_val = newVal;
}
return [_val, setState];
}
const [foo, setFoo] = useState(0);
console.log(foo);
setFoo(1);
console.log(foo);
해당 코드는 useState hook을 구현한 것.
해당 코드에서 foo라는 상태의 초기 값은 0이고 setFoo에 1의 값으로 상태를 변경하면?
나는 1이 나올거라고 생각하고 답했다. 하지만 틀린 답이었고 추가적으로 위의 코드를 어떻게 수정해야할까라는 질문을 받았다.
나는 var 키워드의 문제로 함수 레벨 스코프의 문제인거 같다고 했다.
또 틀렸다.
힌트를 받은 것으로는 원시 타입에 대해서 생각해보라고 하셨는데,
긴장을 너무해서 객체타입을 원시타입이라고 말해버렸다.(뒤에 Number BigInt 어쩌구 하긴했는데 object부터 꺼낸 머리가 문제다.) 잊지말자, Number, String, BinInt, null, Symbol, undefined, Boolean
나지막하게 얕은 복사를 중얼거린거 같은데..
useState(0)가 호출되면 _val라는 변수에 0의 값이 저장된다. useState는 _val과 setState의 값을 반환하고 있는데, 반환된 _val는 값 자체가 복사가되어 foo에 저장된다.
원시타입은 값 자체를 복사하므로 foo는 0의 값을 갖게 된다. 이 시점에서 foo는 _val의 값을 독립적으로 복사한 상태이다.
setState를 호출하면 _val의 값은 새로운 값으로 변한다. 하지만 foo는 이미 이전에 복사한 값을 유지하고 있다.
왜냐면 foo는 _val의 값을 복사했을 뿐이고 _val에 대한 참조를 가지지 않기 때문이다.
그러니까 결론적으로 foo는 _val를 참조하는게 아닌 값만 복사해서 가지고 있기 때문. 마치 깊은 복사처럼.
그래서 결과 값은 0 , 0이 출력된다.
그럼 어떻게 개선해야할까?
function useState(initialValue) {
var _val = { val: initialValue };
function setState(newVal) {
_val.val = newVal;
}
return [_val, setState];
}
const [foo, setFoo] = useState(0);
console.log(foo);
setFoo(1);
console.log(foo);
얕은 복사를 활용하여 객체 타입을 사용하는 방법이다.
원시 타입의 문제를 해결하기 위해서 _val의 값을 객체 타입으로 사용하였다.
왜냐면 얕은 복사는 객체의 참조 주소만 복사하는데 객체 내부의 값이 변하면 모든 참조하고 있는 변수에 영향을 끼친다.
그러니까 객체 타입을 사용하게 되면 값 자체를 복사하는게 아니라 참조 주소만 복사하기 때문에 setState의 값이 변경되면 state의 값도 변경된다.
foo의 상태는 현재 객체의 참조 주소를 가지고 있는데 setState가 호출되어 _val.val의 값이 변경되면, 변경된 값과 같은 참조 주소를 가진 변수에 반영된다.
댓글