1. 순수한 컴포넌트
React에서는 컴포넌트를 "순수하게(Pure)" 작성하는 게 중요하다.
쉽게 말해, 입력값이 같으면 결과도 항상 같아야 한다.
수학공식처럼 y = 2x일 때 x = 2 → y = 4, x = 3 → y = 6
이 함수는 항상 같은 결과를 반환한다.
컴포넌트로 예시를 들어보면, 다음 컴포넌트는 항상 name에 따라 "안녕하세요, name님!" 을 보여준다.
function Greeting({ name }) {
return <h1>안녕하세요, {name}님!</h1>;
}
이처럼 예측 가능한 컴포넌트가 바로 "순수"한 컴포넌트이다.
2. 반대로 순수하지 않은 컴포넌트는?
let randomNumber = Math.random();
function LuckyNumber() {
return <p>당신의 숫자는 {randomNumber}입니다</p>;
}
randomNumber가 외부에서 결정돼서 똑같이 렌더링해도 계속 다른 값이 나올 수 있다.
이런 유형은 예측이 불가하기 때문에 버그로 이어지기 쉽다.
let guest = 0;
function Cup() {
// 나쁜 지점: 이미 존재했던 변수를 변경하고 있습니다!
guest = guest + 1;
return <h2>Tea cup for guest #{guest}</h2>;
}
이 컴포넌트도 guest라는 변수가 컴포넌트 밖에 있어서 언제 렌더링되느냐에 따라 JSX가 달라질 수 있다.
반대로 guest 값을 props로 넘기면, 그 값에 의존하여 JSX를 만들기 때문에 컴포넌트를 순수하게 만들 수 있다!
function Cup({ guest }) {
return <h2>Tea cup for guest #{guest}</h2>;
}
export default function TeaSet() {
return (
<>
<Cup guest={1} />
<Cup guest={2} />
<Cup guest={3} />
</>
);
}
3. 엄격모드로 순수하지 않은 연산 감지
React는 개발 중에 컴포넌트를 두 번 실행해보는 엄격 모드(Strict Mode) 를 지원한다.
❓ 왜 두 번 실행할까?
👉 "순수하지 않은 컴포넌트"를 찾아내기 위해!
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
가끔 개발환경에서 콘솔이 두번 찍히는 이유는 Strict Mode 때문이다...
엄격 모드는 개발환경에서만 동작하며 실제 서비스 배포에는 영향을 주지 않으니 개발중에는 유지하도록 하자
4. 컴포넌트 안에서 변수 바꿔도 될까?
앞에 예시들처럼 React에서는 렌더링 중에 외부 변수를 바꾸면 안 된다!
반대로 컴포넌트 안에서 새로 만든 변수는 바꾸는건 가능하다.
// ✅ 괜찮음
function CupGroup() {
const cups = [];
cups.push(<Cup guest={1} />);
cups.push(<Cup guest={2} />);
return <div>{cups}</div>;
}
여기서 cups는 컴포넌트 안에서 새로 만든 변수니까 렌더링할 때마다 새로 만들어지고, 외부에는 영향이 없다.
이런 걸 지역 변경(local mutation)이라고 부르며 컴포넌트 안에서만 몰래 일어나는 작은 비밀이라고 한다.
몰래 일어나는 작은 비밀?
컴포넌트 내부에서 새로 만든 변수나 배열은 그 렌더링 순간에만 존재하고,
컴포넌트 밖에서는 그 값이 만들어졌는지, 바뀌었는지 전혀 모른다. => 컴포넌트 내부에서 조용히 일어나는 일!
5. 사이드 이펙트⚠️
- 화면이 바뀌고
- 애니메이션이 돌고
- 서버에서 데이터도 바뀌고...
이런 걸 전부 "사이드 이펙트(side effect)"라고 말한다. → 렌더링 자체와는 별도로, "옆에서" 일어나는 일들
function Button() {
function handleClick() {
console.log('버튼 클릭됨!'); // 사이드 이펙트
}
return <button onClick={handleClick}>클릭</button>;
}
리액트는 사이드 이펙트를 보통 이벤트 핸들러에서 처리한다. 버튼을 누른 시점에 일어나기 때매 렌더링할 때 실행되는 게 아니다.
→ 그래서 이벤트 핸들러 안에서는 마음껏 사이드 이펙트를 써도 된다!
* 그래도 이벤트로 처리할 수 없다면?
예를 들어 컴포넌트가 처음 렌더링될 때 데이터를 불러와야 한다면? (사용자 이벤트 없이도 자동으로 동작해야함)
이때는 useEffect를 사용할 수 있다.
import { useEffect } from 'react';
function Profile() {
useEffect(() => {
// 컴포넌트가 화면에 나타난 직후 실행됨
fetchUserProfile();
}, []);
return <p>사용자 정보를 불러오는 중...</p>;
}
useEffect는 렌더링이 끝난 이후 실행되기 때문에 그 안에서 사이드 이펙트를 안전하게 처리할 수 있다.
단, 이 방식은 최후의 수단으로 사용하는 것이 좋다.(가능한 렌더링만으로 처리하는게 예측가능하고 유지보수하기 쉬움)
'기술 > React.js' 카테고리의 다른 글
[문서] 리액트 공식문서 톱아보기: 컴포넌트 import 및 export (1) | 2024.11.16 |
---|---|
[문서] 리액트 공식문서 톱아보기: 리액트에서 key가 중요한 이유는? (5) | 2024.11.06 |
[문서] 리액트 공식문서 톱아보기: 컴포넌트 (0) | 2024.10.28 |
[문서] 리액트 공식문서 톱아보기: 기본 문법(빠른 시작 가이드) (1) | 2024.10.27 |
react에서 vite로 env 설정해서 proxy 사용하기 (+CRA에서 proxy 설정) (0) | 2024.03.20 |