리액트에서 절대 하면 안되는 것
리액트에서 절대 하면 안되는 것이 하나 있다.
컴포넌트 함수 밖에 let
으로 변수 선언을 하면 절대 안 된다.
잘못된 코드
// import 생략 ...
let count = 1;
function WrongComponent() {
const [_, setCount] = useState(1);
const onClick = useCallback(() => {
setCount(count++);
}, []);
return <div onClick={onClick}>count: {count}</div>;
}
export default WrongComponent;
문제 생각해보기
위처럼 코드를 작성하면, 위 컴포넌트를 페이지당 1개 쓸 때는 크게 문제가 없을 수도 있지만, 컴포넌트 밖 중복되는 이름의 let
변수가 있을 때 해당 변수를 공유하게 될 수 있다.
function MainComponent() {
return (
<div>
<WrongComponent />
<WrongComponent />
<WrongComponent />
<WrongComponent />
</div>
);
}
위와 같이 메인 컴포넌트를 구성한다고 했을 때, 저 4개의 WrongComponent
는 같은 count
를 공유하게 된다. 그러면서도 렌더링 시점은 각각 달라서 위에서부터 차례대로 클릭했을 때 맨위는 1, 그 다음은 2, 그 다음은 3, 그 다음은 4 이런식으로 렌더링 시점 때문에 또 미묘한 동작이 일어나게 된다.
실무의 복잡한 상황에서 이러한 실수를 하게 되면 찾기 매우 어려우니 주의하자.
실무에서는 멀리 떨어진 각각의 코드로 보이는 것들이 같은 값을 공유하는 현상이 생긴다. 이 경우 디버깅하기 매우 어렵다.
원인 생각해보기
import WrongComponent from './WrongComponent';
와 같이 import
를 수행하면, 위에 작성했던 let count = 1
이 한번 선언되고, 모든 컴포넌트는 이 단 한번 선언된 변수를 공유하여 이용하게 된다.
왜 const
는 문제가 없을까?
const
는 애초에 수정될 수도 없을 뿐더러, 고정된 값이라 전역으로 사용해도 보통 전혀 문제가 없기 때문이다.
그러나 이렇게 해도될 때
import { useCallback } from "react";
import { io, Socket } from "socket.io-client";
import Config from "react-native-config";
let socket: Socket | undefined;
const useSocket = (): [Socket | undefined, () => void] => {
const disconnect = useCallback(() => {
if (socket) {
socket.disconnect();
socket = undefined;
}
}, []);
if (!socket) {
socket = io(`${Config.API_URL}`, {
transports: ["websocket"],
});
}
return [socket, disconnect];
};
export default useSocket;
위처럼 소켓 통신 세션을 딱 1번만 열고 열어놓은 세션을 재활용하고 싶다면, 이를 오히려 이용할 수도 있긴 하다.
레퍼런스
'프론트엔드 > React' 카테고리의 다른 글
React Effect Hook 이란? (0) | 2022.10.19 |
---|---|
React 컴포넌트 어떻게 나누고 재사용할 것인가? (0) | 2022.07.24 |
React Hook Form 이 해결하는 문제들과 사용법 (0) | 2022.07.02 |
React Hook Form 소개 (0) | 2022.07.02 |