[ 요약 ]
- 컴포넌트는 순수해야함
- 렌더링전에 존재했던 객체나 변수를 변경 ❌
- 같은 입력 → 같은 결과
- React는 작성되는 모든 컴포넌트가 순수 함수일 거라 가정
React 컴포넌트가 같은 입력이 주어진다면 반드시 같은 JSX를 반환한다
- 렌더링 이전에 존재했던 객체나 변수를 변경하지 않는, 컴포넌트를 순수하게 하는 JSX 만 반환해야함
- 동일한 렌더링동안 생성된 그냥 만든 변수와 객체를 변경하는 것은 문제 ❌
- 특정 순서로 컴포넌트 렌더링 기대 ❌ → 독립적으로 JSX 연산
- 이벤트 핸들러가 컴포넌트 내부에 정의되었다 하더라도 렌더링 중에는 실행 ❌ (이벤트 핸들러는 순수할 필요 ❌)
- 변화 (화면 업데이트, 데이터 변경)를
side effect
라고 하며, 보통 이벤트 핸들러에 포함- 웬만하면 렌더링만으로 로직 표현하고 useEffect는 마지막 수단으로 사용
[ 학습 내용 ]
순수성
이란 무엇인지 그리고 어떻게 버그를 피하도록 도울 건지 배웁니다.- 렌더 단계에서 변화를 유지하면서 컴포넌트를 순수하게 유지할 것인지 배웁니다.
- 엄격 모드를 어떻게 활용해서 컴포넌트에 실수를 발견할 수 있는지 배웁니다.
컴퓨터 과학에서 순수함수
의 특징 (특히 함수형 프로그래밍의 세계)
React는 이러한 컨셉을 기반으로 설계되었음
React는 작성되는 모든 컴포넌트가 순수 함수일 거라 가정
이러한 가정은 작성되는 React 컴포넌트가 같은 입력이 주어진다면 반드시 같은 JSX를 반환한다
는 것을 의미
ex) drinkers에 2를 전달하면 Recipe는 항상 2 cups of water 를 반환
function Recipe({ drinkers }) {
return (
<ol>
<li>Boil {drinkers} cups of water.</li>
<li>Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.</li>
<li>Add {0.5 * drinkers} cups of milk to boil and sugar to taste.</li>
</ol>
);
}
export default function App() {
return (
<section>
<h1>Spiced Chai Recipe</h1>
<h2>For two</h2>
<Recipe drinkers={2} />
<h2>For a gathering</h2>
<Recipe drinkers={4} />
</section>
);
}
“React의 렌더링 과정은 항상 순수해야한다.”
렌더링 이전에 존재했던 객체나 변수를 변경하지 않는, 컴포넌트를 순수하게 하는 JSX 만 반환해야함
이러한 규칙을 위반하는 컴포넌트 예시 코드
let guest = 0;
function Cup() {
// 나쁜 지점: 이미 존재했던 변수를 변경하고 있다!
guest = guest + 1;
return <h2>Tea cup for guest #{guest}</h2>;
}
export default function TeaSet() {
return (
<>
<Cup />
<Cup />
<Cup />
</>
);
}
컴포넌트 바깥에 선언된 guest 변수를 수정
→ 컴포넌트가 여러번 호출되면 다른 JSX를 생성한다는 것을 의미
다른 컴포넌트가 guest를 읽었다면 언제 렌더링되었는지에 따라 그 컴포넌트 또한 다른 JSX를 생성함
→ 예측 ❌, 의도한 결과 ❌
guest
변수 대신 props로 넘겨 이 컴포넌트를 고칠 수 있음
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} />
</>
);
}
위에서 JSX가 반환되는 것은 오직 guest 에 의존하기 떄문에 순수한 컴포넌트
특정 순서로 컴포넌트 렌더링 기대 ❌ → 독립적
으로 JSX 연산
각 컴포넌트는 렌더링 중에 다른 컴포넌트를 의존하지 말고 자체적으로 JSX를 연산해야함
React가 렌더링하면서 읽을 수 있는 3가지 종류의 입력 요소 : props
, state
, context
사용자의 입력에 따라 무언가를 변경 → setState
컴포넌트가 렌더링되는 동안에는 기존 변수나 개체를 변경하면 안됨
strict mode
: 개발 중에 각 컴포넌트의 함수를 두 번 호출
순수 함수는 두 번 호출되더라도 정상적으로 동작 (같은 입력 → 같은 출력)
production에 영향을 주지 않기 때문에 사용자의 앱 속도가 느려지지 않음
[ 문제 상황 ]
렌더링하는 동안 컴포넌트가 기존 변수를 변경했다는 것
순수 함수 → 함수 스코프 밖에 변수나 호출 전에 생성된 객체를 변경하지 않음
But, 렌더링하는 동안 그냥 만든 변수와 객체를 변경하는 것
은 문제 ❌
function Cup({ guest }) {
return <h2>Tea cup for guest #{guest}</h2>;
}
export default function TeaGathering() {
let cups = [];
for (let i = 1; i <= 12; i++) {
cups.push(<Cup key={i} guest={i} />);
}
return cups;
}
TeaGathering 컴포넌트 안에 동일한 렌더링 중에 생성되었기 때문에 ✅ (컴포넌트 바깥에 선언 시 문제)
→ 지역 변형
(TeaGathering 외부에서는 모름)
함수형 프로그래밍은 순수성
에 크게 의존 → 어떻게 바꿈?
변화 (화면 업데이트, 애니메이션 시작, 데이터 변경) : side effect
side effect는 보통 이벤트 핸들러에 포함
이벤트 핸들러가 컴포넌트 내부에 정의되었다 하더라도 렌더링 중에는 실행 ❌
→ 그래서 이벤트 핸들러는 순수할 필요 ❌
적합한 이벤트 핸들러를 찾을 수 없는 경우, useEffect
를 호출하여 반환된 JSX에 해당 이벤트 핸들러 연결
side effect가 허용될 때 렌더링 후 나중에 실행하도록 지시 → useEffect는 마지막 수단으로 사용
=> 웬만하면 렌더링만으로 로직 표현하기