Strict Mode란
React의 Strict Mode는 react의 내부 구성 요소에 대한 발생 가능한 잠재적 문제를 사전에 알아내기 위한 도구이다.
문제가 발생할 경우 로그가 출력되며 이는 개발모드에서만 동작하도록 되어있다.
공식문서에 정의된 사용하기 위한 문법은 아래와 같다.
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
);
공식문서에서는 react app을 위와같이 Strict Mode로 감싸서 사용하는 것을 권장하고 있으며 이를 통해 발생 가능한 버그들을 사전에 수정하라고 제시하고 있다.
useEffect와 Strict Mode
Strict Mode안쪽에서의 useEffect는 예상과는 조금 다르게 동작한다.
Strict Mode가 활성화되면 React는 개발 환경에서 추가적인 setup과 cleanup 사이클을 실행하는데 이로 인해 Effect의 setup과 cleanup을 총 2번 실행되게된다. 이를 통해 개발환경에서 찾아내기 힘든 미묘한 버그를 찾아낼 수 있다.
감이 안잡힐 수 있는데 공식 문서에 정의된 문제 예시를 통해 알아보도록 하자.
[코드]
// App.js
import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';
const serverUrl = '<https://localhost:1234>';
const roomId = 'general';
export default function ChatRoom() {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
}, []);
return <h1>Welcome to the {roomId} room!</h1>;
}
// chat.js
let connections = 0;
export function createConnection(serverUrl, roomId) {
// A real implementation would actually connect to the server
return {
connect() {
console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...');
connections++;
console.log('Active connections: ' + connections);
},
disconnect() {
console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl);
connections--;
console.log('Active connections: ' + connections);
}
};
}
[결과]
// 결과
✅ Connecting to "general" room at <https://localhost:1234>...
Active connections: 1
위 코드에는 잠재적인 문제가 존재하지만 결과만 봤을 때에는 괜찮아 보인다.
문제를 좀 더 명확하게 하기위해 기능을 하나 추가해보자
[코드]
// App.js
import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';
const serverUrl = '<https://localhost:1234>';
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
}, [roomId]);
return <h1>Welcome to the {roomId} room!</h1>;
}
export default function App() {
const [roomId, setRoomId] = useState('general');
const [show, setShow] = useState(false);
return (
<>
<label>
Choose the chat room:{' '}
<select
value={roomId}
onChange={e => setRoomId(e.target.value)}
>
<option value="general">general</option>
<option value="travel">travel</option>
<option value="music">music</option>
</select>
</label>
<button onClick={() => setShow(!show)}>
{show ? 'Close chat' : 'Open chat'}
</button>
{show && <hr />}
{show && <ChatRoom roomId={roomId} />}
</>
);
}
기존 general 로 하드코딩 되어있던 roomId를 드롭다운을 통해 선택 가능하도록 변경했다. 이후 연결을 테스트해보면 콘솔에서 연결 수가 계속해서 증가하는 문제가 발생하는 것을 확인할 수 있다.
[코드]
// 결과
✅ Connecting to "general" room at <https://localhost:1234>...
Active connections: 1
✅ Connecting to "travel" room at <https://localhost:1234>...
Active connections: 2
✅ Connecting to "music" room at <https://localhost:1234>...
Active connections: 3
이 문제의 원인은 기존의 Effect 내부에 cleanup 함수가 없어서 disconnect가 발생하지 않아 연결이 무한히 증가할 수 있게 된다는 점이다. 따라서 코드를 아래와 같이 수정하면 정상적으로 동작하게 된다.
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]);
하지만 이 문제는 select를 추가하여 테스트 해보기 전까지는 명확하게 밝혀지지 않은 잠재적인 문제였다고 말할 수 있다. 이는 간단한 예시이지만 규모가 큰 프로젝트에서는 더 복잡한 코드일테고 그 상황에서는 이러한 문제들을 찾기 어려울 것이다.
만약 위 코드가 Strict Mode로 감싸진 개발 환경에서 동작한다고 가정해보면 어떨까? 메인 코드를 아래와 같이 Strict Mode로 감싸주고 테스트를 진행해보았다.
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';
import App from './App';
const root = createRoot(document.getElementById("root"));
root.render(
<StrictMode>
<App />
</StrictMode>
);
// 결과
✅ Connecting to "general" room at <https://localhost:1234>...
Active connections: 1
✅ Connecting to "general" room at <https://localhost:1234>...
Active connections: 2
Strict Mode로 감싼 이후의 결과 값을 보면 위와 같이 이상한 점을 바로 찾을 수 있게 된다.
결론
Strict Mode는 개발 초기에 실수를 발견하고 해결하는 데 중요한 역할을 한다. 개발자가 놓치기 쉬운 이슈를 콘솔 로그를 통해 명확하게 드러내며, 위에서 본 것과 같은 잠재적인 버그를 해결하는 데 도움을 준다.
React 18로 넘어오면서 Render Phase 동작이 바뀌었고 이로 인해 멱등성이 깨질 가능성이 생기게 되었다. React 18에서는 useEffect가 여러번 실행될 때 멱등성을 보장하는것을 표면적으로 보여지도록 하기위해 즉 렌더링 횟수에따라 결과가 바뀌는 것을 방지하기 위해 Strict Mode에 해당 기능을 추가하였다.
Strict Mode는 Effect의 setup > cleanup > setup 로직을 실행하여, 특히 컴포넌트가 변경될 때마다 발생할 수 있는 버그를 찾아내는 데 유용하며 이를 통해 컴포넌트의 멱등성을 어느정도 보장해준다.
이러한 문제들은 실제 애플리케이션에 큰 영향을 미칠 수 있으므로, Strict Mode를 사용하여 개발 단계에서 애플리케이션의 안정성과 성능 문제를 미리 예방하는 것이 좋다.
'frontend' 카테고리의 다른 글
프론트엔드 전체 테스트 환경 구축해보기(2.CLI) (0) | 2024.08.30 |
---|---|
프론트엔드 전체 테스트 환경 구축해보기(1.설계) (0) | 2024.08.22 |
React Lane 간단 정리 (0) | 2024.08.03 |
React Fiber동작 간단 정리 (0) | 2024.08.02 |
React19 Support for Document Metadata / stylesheets / async scripts / preloading resources (2) | 2024.06.04 |