const MyReact = (function () {
let _val;
return {
render(Component) {
const Comp = Component();
Comp.render();
return Comp;
},
useState(initialValue) {
_val = _val || initialValue;
function setState(newVal) {
_val = newVal;
}
return [_val, setState];
},
};
})();
function Counter() {
const [count, setCount] = MyReact.useState(0);
const [text, setText] = MyReact.useState("test");
return {
click: () => {
setCount(count + 1);
MyReact.render(Counter);
},
change: () => {
setText("hello");
MyReact.render(Counter);
},
render: () => console.log("render:", { count, text }),
};
}
let App = MyReact.render(Counter);
App.click();
App.change();
위의 코드가 초기에 마운트 되었을 때 render: {count: 0, text: 'test'}가 출력된다.
App.click()함수가 실행될 때와 App.change()함수가 실행될 때는 뭐가 출력될까?
나는 click함수가 실행되면 {count: 0, text: 'test'} 그대로 출력될거라고 말했다. 이유는 setCount의 값이 count를 그대로 참조하고 있으며, 리액트에서 상태가 변경되면 가상 돔은 변경된 값과 기존의 값을 비교해서 리렌더링 하는데 내가 말한 이유는 count의 값을 직접 참조하게 되면 상태는 변하지만 가상돔이 업데이트되지않아 ui는 그대로 0으로 보일거라고 했다.
멍청한 머리, 멍청한 머리...count를 직접적으로 변경하고 있는게 아닌데, 완전 새하얗게 되버려서 나오는데로 말해버렸다. 내가 말한게 맞을려면 setCount 대신에 count = count + 1이 되었어야한다.
이거 며칠전에 봤었는데 진짜 멍청한 머리
위 코드의 문제는 useState 함수에서 사용되는 _val의 값이 하나의 값만 저장하기 때문에 발생한 문제이다.
그래서 count와 text가 동일한 _val를 공유하게 되는데 하나의 상태를 업데이트하면 다른 상태도 같이 변경되어버린다.
render: {count: 0, text: 'test'}
render: {count: 1, text: 1}
render: {count: 'hello', text: 'hello'}
이렇게 출력된다.
이를 해결하기 위해서 _val값을 저장할 배열을 만들고 상태에 대한 index관리를 해줘야한다고 한다.
const MyReact = (function () {
let _vals = []; // 상태 값들을 저장할 배열
let _index = 0; // 상태 인덱스 관리
return {
render(Component) {
_index = 0; // 렌더링 시 상태 인덱스 초기화
const Comp = Component();
Comp.render();
return Comp;
},
useState(initialValue) {
const currentIndex = _index; // 현재 상태 인덱스를 저장
_vals[currentIndex] = _vals[currentIndex] || initialValue; // 초기 상태 설정
function setState(newVal) {
_vals[currentIndex] = newVal; // 해당 인덱스의 상태값을 업데이트
}
_index++; // 다음 상태로 인덱스 증가
return [_vals[currentIndex], setState];
},
};
})();
function Counter() {
const [count, setCount] = MyReact.useState(0);
const [text, setText] = MyReact.useState("test");
return {
click: () => {
setCount(count + 1);
MyReact.render(Counter);
},
change: () => {
setText("hello");
MyReact.render(Counter);
},
render: () => console.log("render:", { count, text }),
};
}
let App = MyReact.render(Counter);
App.click();
App.change();
useState의 동작원리...그냥 막연하게 클로져랑 관련이있다 카더라~ 라고만 듣고 넘겼는데 신선한 충격이었다.
그냥 js기술만 보던 나는 그냥 뭐하는 놈인거지 생각함.
왜 라는 의문을 가져야한다고 했다. 왜 라는 의문을 가지자. 뭐든 된다고 넘기지 말고 왜 이게 되는지를 알아가자.
댓글