추상화의 단위를 함수로 사용하는 것이 함수형 프로그래밍이다.
interface Props {
menu: ReactNode;
}
export const Layout = ({ menu }: Props) => {
return <div>{menu}</div>;
};
const App = () => {
return <Layout menu={<div>menu here</div>} />
}
리액트는 jsx, tsx 문법으로 컴포넌트를 구성한다.
사실 Layout 같은 태그는 실제 html 태그는 아니고 인자를 받아서 컴포넌트 안의 함수를 실행시킨다. 그리고 그 결과로 완성된 dom 구조를 얻을 수 있다.
그러므로 Layout 컴포넌트가 menu라는 ReactNode 타입의 인자를 받아서 리턴한다는 의미는 "Layout이라는 이름의 함수가 menu라는 이름의 함수를 인자로 받아서 실행"하는 "고차함수"라는 이야기가 된다.
여기서 menu 함수로 추상화했으므로 리액트는 함수형 프로그래밍이 될 수 있다.
하지만 위와 같은 코드로는 컴포넌트마다 상태를 가지고 있지 않는다. 메뉴를 보였다가 안보이게 하는 등, 상태 관리가 불가피할 때 리액트 hook 중 가장 기본이 되는 useState 를 사용할 수 있다.
export const Layout = ({ menu }: Props) => {
const [isMenuActive, setIsMenuActive] = useState<boolean>(false);
return (
<div style={{ visibility: isMenuActive ? "visible" : "hidden" }}>
<button onClick={() => setIsMenuActive(!isMenuActive)}> menu button </button>
{menu}
</div>
);
};
Layout은 함수로 알고 있고 함수가 실행했을 때 false로 초기화된 이후로 변경은 어렵지 않을까라는 의문이 들었다.useState를 호출했을 때 리액트로부터 받는 상태 값과 상태를 업데이트할 수 있는 함수를 가지고 상태를 관리한다.setState(상태를 업데이트할 수 있는 함수)는 상태값 변경하고 리랜더링을 한다아래 예시는 클로지를 캡처한 예시이다.
(콘솔 출력 시점은 가장 처음 버튼을 누른 시점이다.)
export const Counter = () => {
const [count, setCount] = useState<number>(0);
const countDouble = () => {
console.log(count); // 0
setCount(prev => prev + 1)
console.log(count); // 0
}
return (
<>
<button onClick={countDouble}> count 2 </button>
<span>{count}</span> // <span>1</span>
</>
);
}
countDouble이 실행했을 시점에 count는 0이다. 현재 캡처된 값은 초기화 상태인 0이기 때문이다.<span>1</span> 은 랜더링 시점의 상태값이므로 변경된 상태값이 출력되었다.setCount(prev => prev + 1) 과 setCount(count+1) 두 변경 방식이 있는데 전자 방식이 '리액트'가 제공하는 가장 최신 상태값을 참조하기 때문에 안전하다.위 예시에서 살짝 다른 예시이다.
export const Counter = () => {
const [count, setCount] = useState<number>(0);
--------------------------
const count = () => {
setCount(1)
setCount(2)
}
--------------------------
return (
<>
<button onClick={count}> count </button>
<span>{count}</span> //<span>2</span>
</>
);
}
setState가 두 번 불렸으니 두 번 리랜더링한다고 생각할 수 있지만 리액트는 배칭을 사용한다.
배칭은 성능을 최적화하기 위해 업데이트 큐에 상태 업데이트를 넣어 상태 업데이트를 한 번에 처리하는 방식이다.
랜더링은 시간이 걸리는 작업이므로 두 번 랜더링할 거 한 번에 해버리니 배칭은 중요한 작업임이 틀림없다.