클래스형 컴포넌트들은 method의 개념이므로, 리렌더링이 되더라도 render() 를 제외한 나머지 method 및 state는 그대로 보존이 되어 있음.
함수형 컴포넌트들은 기본적으로 리렌더링이 될때, 함수 안에 작성된 모든 코드가 다시 실행되며 함수형 컴포넌트들이 기존에 가지고 있던 상태(state)를 전혀 관리(기억)할 수 없게 만듦
⇒ Stateless Component
단순하게 React에서의 state 만을 의미하는 것이 아닌, 함수내에 써져 있는 모든 코드 및 변수를 기억할 수 없다는 의미
⇒ 함수형 컴포넌트가 리렌더링될때 무조건 새롭게 선언 & 초기화 & 메모리에 할당이 됨
하지만 Hook의 등장으로, 브라우저에 메모리를 할당 함으로써, 함수형 컴포넌트가 상태(state)를 가질 수 있게 한 것. 즉, 함수 내에 써져있는 코드 및 변수를 기억할 수 있게 됐음을 의미
1) 컴포넌트 사이에서 상태 로직 재사용의 어려움 -> render props, HOC 등
2) 복잡한 (클래스형) 컴포넌트들은 이해하기 어려움 -> 각종 생명주기 함수들
3) 클래스자체 개념을 이해하기 어려움 -> this 등
💡 추가로 공부할 것 : Hook의 성능 최적화 방법
클로저는 함수가 속한 렉시컬 스코프를 기억하여 함수가 렉시컬 스코프 밖에서 실행될 때에도 이 스코프에 접근할 수 있게 하는 기능을 뜻한다.
function useFoo() {
let foo = 0;
function getFoo() {
return foo;
}
function setFoo(value) {
foo = value
}
return [getFoo, setFoo];
}
// 사용하는 측
const [getFoo, setFoo] = useFoo();
console.log(getFoo()); // 0
setFoo(1);
console.log(getFoo()); // 1
const useState = (initialValue) => {
let value = initialValue;
const state = () => value;
const setState = (newValue) => {
value = newValue;
};
return [state, setState];
};
const [counter, setCounter] = useState(0);
console.log(counter()); // 0
setCounter(1);
console.log(counter()); // 1
💡 추가적으로 공부해야 할 것 : 각 Hooks의 세부적인 동작원리
const useState = (initialValue) => {
let state = initialValue;
const setState = (newValue) => {
state = newValue;
};
return [state, setState];
};
const [counter, setCounter] = useState(0);
console.log(counter); // 0
setCounter(1);
console.log(counter); // 0 → Error!
const MyReact = (function () {
let state;
return {
render(Component) {
const Comp = Component();
Comp.render();
return Comp;
},
useState(initialValue) {
state ||= initialValue;
const setState = (newValue) => {
state = newValue;
};
return [state, setState];
},
};
})();
const Counter = () => {
const [count, setCount] = MyReact.useState(0);
return {
click: () => setCount(count + 1),
render: () => console.log('render:', { count }),
};
};
let App;
App = MyReact.render(Counter); // render: { count: 0 }
App.click();
App = MyReact.render(Counter); // render: { count: 1 }
let state = [];
let setters = [];
let cursor = 0;
let firstrun = true;
const createSetter = (cursor) => {
return (newValue) => {
state[cursor] = newValue;
};
};
const useState = (initialValue) => {
if (firstrun) {
state.push(initialValue);
setters.push(createSetter(cursor));
firstrun = false;
}
const resState = state[cursor];
const resSetter = setters[cursor];
cursor++;
return [resState, resSetter];
};
두 규칙을 따랐을 때 컴포넌트가 렌더링 될 때마다 동일한 순서로 hook이 호출되는 것을 보장.