React를 이제 배우기 시작한 단계에서 야무 쌤께서 강조하셨던 순수성, 그리고 이를 위해 Side Effect를 어떻게 처리해야하는지,
아직 정확하게 설명할 순 없기에 이번 기회에 정리해보고, 두고두고 보려한다.
순수성(Purity)
리액트에서 순수성을 강조하는 것은 리액트 동작 원칙과 코드 효율성 향상 사이의 밀접한 관계를 반영한 것이라고 한다.
순수함이란? 보통 순수 함수를 말하며, 순수 함수를 사용하면 어플리케이션의 일관성 및 예측 가능성이 높아지고, 코드 재사용이 쉬워져서 개발 및 유지보수 프로세스를 효율적으로 만들어 준다는 차원에서 권장된다.
순수 함수:
동일 입력값에 따라 동일 출력값을 반환하는 함수 + 함수의 외부영역에 부수효과(Side Effect)가 없는 함수
부수 효과(Side Effect):
부수 효과란, 함수 내부에서 발생하는 외부 세계와의 상호 작용으로, 함수의 인자, 반환 값에만 의존하지 않고 외부 상태에 의존하거나 외부 상태를 변경하거나, I/O 작업(네트워크 요청, DOM 조작 등)을 수행하는 것 등이 포함됩된다.
예제1 (순수함수)
x, y 매개변수에 의해 순수하게 계산된 결과만 반환한다.
function add(x, y) {
return x + y;
}
예제2 (순수하지 않은 함수)
- selector가 추가/제거될 경우 반환되는 요소가 달라질 수 있다(getNode)
- node 객체의 상태를 직접 변경하여 외부 상태 변경(addClass)
function getNode(selector, context = document) {
return context.querySelector(selector);
}
function addClass(node, className) {
node.classList.add(className);
return node;
}
예제3 (순수하지 않은 함수)
- 서버에 데이터를 요청하는 과정이 포함되면, 서버 상태나 입력값 처리 방식에 따라 동일한 입력에 대해 동일한 출력을 보장할 수 없다.
- 함수 외부 상태에 의존하여 네트워크 상태나 서버에서 반환되는 응답에 따라 결과 달라진다.
- 순수 함수는 외부 환경에 영향을 주지 않고, 고립된 상태에서 실행되어야 하므로 네트워크 요청을 수행하는 것 자체가 부수효과이다.
async function sendMessage(emailAddress, message) {
const response = await fetch(
`https://send-message.com/api/message?email=${emailAddress}&message=${message}`
);
if (!response.ok) {
throw new Error('이메일에 메시지 전송에 실패했습니다.');
}
return response;
}
예제4 (순수 컴포넌트와 순수하지 않은 컴포넌트)
// ThisIsPure.jsx
function ThisIsPure({ whatIsPure, isThisPure }) {
return (
<ul>
<li>
<h2>순수함이란?</h2>
<p>{whatIsPure}</p>
</li>
<li>
<h2>이것은 순수한가요?</h2>
<p>{isThisPure ? '네!' : '아니오..'}</p>
</li>
</ul>
);
}
function ThisIsImpure({ whatIsPure, isThisPure }) {
const randomMessage = `나의 말은 늘 정직하다. - ${Math.random()}`;
return (
<ul>
<li>
<h2>순수함이란?</h2>
<p>
{whatIsPure} {randomMessage}
</p>
</li>
<li>
<h2>이것은 순수한가요?</h2>
<p>{isThisPure ? '네!' : '아니오..'}</p>
</li>
</ul>
);
}
- ThisIsPure 컴포넌트:
- 동일한 입력(props)에 대해 동일한 출력(JSX)을 반환한다.
- 외부 상태에 의존하지 않고, 외부 상태를 변경하지 않다.
- 사이드 이펙트가 없다.
- ThisIsImpure 컴포넌트:
- 동일한 입력(props)에 대해 동일한 출력(JSX)을 반환하지 않습니다. 이는 함수 내부에서 Math.random()을 사용하여 무작위로 변경되는 메시지가 포함되기 때문이다.
- 외부 상태에 의존하지 않지만, 사이드 이펙트가 있다. (함수 내에서 Math.random() 사용)
리액트에서 순수성을 지키기 위해 컴포넌트를 만들 때 지켜야 할 것.
- 컴포넌트 렌더링 단계에 영향을 미치지 않도록 순수함을 유지해야 한다. => 컴포넌트의 반환 값이 동일한 prop 값에 대해 일관되게 유지되어야 하며, 렌더링은 언제든 발생할 수 있으므로 컴포넌트는 서로의 렌더링 순서에 의존해서는 안 된다.
- 사이드 이펙트(부수 효과)를 유발하는 코드를 함수 몸체(body) 안에 작성해서는 안 된다. => useEffect나 useCallback, useRef, useReducer같은 훅들을 사용하여 부수효과 관련 작업을 처리해야 함
- 동일 입력, 동일 출력을 지켜야 한다. (props(읽기 전용) → JSX 반환) => 컴포넌트의 일관성과 가독성, 예측가능성을 향상시키기 위한 것으로, 컴포넌트가 렌더링에 사용되는 입력(props, state, context)을 변경해서는 안 된다.
- StrictMode 컴포넌트의 역할은 계산이 순수한지 확인하는 것이다. (2번씩 렌더링)
- StrictMode는 배포(production) 모드에서 제거되므로 성능에 영향을 주지 않는다.
- 로컬 뮤테이션은 컴포넌트 함수 내부에서 이뤄져도 문제가 되지 않는다. => 함수 내부에서 사용되는 변수나 상태를 변경하는 것은 허용되지만, 외부에서 참조되는 변수나 상태 변경시 순수성이 깨질 수 있다. 화면을 업데이트 하려면 기존 객체를 변경하는 대신 상태(State)를 설정해야 한다.
// 로컬 뮤테이션: 컴포넌트 함수 내부에서만 사용되고 변경되는 변수나 상태를 의미하며, 외부에서 참조되지 않고 함수 내부 로직에만 영향을 주는 경우로 다음과 같은 경우에 사용된다.
- 반복문 내에서 인덱스 변수를 변경하는 경우
- 함수 내에서 임시 변수하고 변경하여 값을 계산하는 경우
- 배열이나 객체를 함수 내부에서 만들고 내부 로직에 따라 조작한 후 반환하는 경우
참고자료
React를 이제 배우기 시작한 단계에서 야무 쌤께서 강조하셨던 순수성, 그리고 이를 위해 Side Effect를 어떻게 처리해야하는지,
아직 정확하게 설명할 순 없기에 이번 기회에 정리해보고, 두고두고 보려한다.
순수성(Purity)
리액트에서 순수성을 강조하는 것은 리액트 동작 원칙과 코드 효율성 향상 사이의 밀접한 관계를 반영한 것이라고 한다.
순수함이란? 보통 순수 함수를 말하며, 순수 함수를 사용하면 어플리케이션의 일관성 및 예측 가능성이 높아지고, 코드 재사용이 쉬워져서 개발 및 유지보수 프로세스를 효율적으로 만들어 준다는 차원에서 권장된다.
순수 함수:
동일 입력값에 따라 동일 출력값을 반환하는 함수 + 함수의 외부영역에 부수효과(Side Effect)가 없는 함수
부수 효과(Side Effect):
부수 효과란, 함수 내부에서 발생하는 외부 세계와의 상호 작용으로, 함수의 인자, 반환 값에만 의존하지 않고 외부 상태에 의존하거나 외부 상태를 변경하거나, I/O 작업(네트워크 요청, DOM 조작 등)을 수행하는 것 등이 포함됩된다.
예제1 (순수함수)
x, y 매개변수에 의해 순수하게 계산된 결과만 반환한다.
function add(x, y) {
return x + y;
}
예제2 (순수하지 않은 함수)
- selector가 추가/제거될 경우 반환되는 요소가 달라질 수 있다(getNode)
- node 객체의 상태를 직접 변경하여 외부 상태 변경(addClass)
function getNode(selector, context = document) {
return context.querySelector(selector);
}
function addClass(node, className) {
node.classList.add(className);
return node;
}
예제3 (순수하지 않은 함수)
- 서버에 데이터를 요청하는 과정이 포함되면, 서버 상태나 입력값 처리 방식에 따라 동일한 입력에 대해 동일한 출력을 보장할 수 없다.
- 함수 외부 상태에 의존하여 네트워크 상태나 서버에서 반환되는 응답에 따라 결과 달라진다.
- 순수 함수는 외부 환경에 영향을 주지 않고, 고립된 상태에서 실행되어야 하므로 네트워크 요청을 수행하는 것 자체가 부수효과이다.
async function sendMessage(emailAddress, message) {
const response = await fetch(
`https://send-message.com/api/message?email=${emailAddress}&message=${message}`
);
if (!response.ok) {
throw new Error('이메일에 메시지 전송에 실패했습니다.');
}
return response;
}
예제4 (순수 컴포넌트와 순수하지 않은 컴포넌트)
// ThisIsPure.jsx
function ThisIsPure({ whatIsPure, isThisPure }) {
return (
<ul>
<li>
<h2>순수함이란?</h2>
<p>{whatIsPure}</p>
</li>
<li>
<h2>이것은 순수한가요?</h2>
<p>{isThisPure ? '네!' : '아니오..'}</p>
</li>
</ul>
);
}
function ThisIsImpure({ whatIsPure, isThisPure }) {
const randomMessage = `나의 말은 늘 정직하다. - ${Math.random()}`;
return (
<ul>
<li>
<h2>순수함이란?</h2>
<p>
{whatIsPure} {randomMessage}
</p>
</li>
<li>
<h2>이것은 순수한가요?</h2>
<p>{isThisPure ? '네!' : '아니오..'}</p>
</li>
</ul>
);
}
- ThisIsPure 컴포넌트:
- 동일한 입력(props)에 대해 동일한 출력(JSX)을 반환한다.
- 외부 상태에 의존하지 않고, 외부 상태를 변경하지 않다.
- 사이드 이펙트가 없다.
- ThisIsImpure 컴포넌트:
- 동일한 입력(props)에 대해 동일한 출력(JSX)을 반환하지 않습니다. 이는 함수 내부에서 Math.random()을 사용하여 무작위로 변경되는 메시지가 포함되기 때문이다.
- 외부 상태에 의존하지 않지만, 사이드 이펙트가 있다. (함수 내에서 Math.random() 사용)
리액트에서 순수성을 지키기 위해 컴포넌트를 만들 때 지켜야 할 것.
- 컴포넌트 렌더링 단계에 영향을 미치지 않도록 순수함을 유지해야 한다. => 컴포넌트의 반환 값이 동일한 prop 값에 대해 일관되게 유지되어야 하며, 렌더링은 언제든 발생할 수 있으므로 컴포넌트는 서로의 렌더링 순서에 의존해서는 안 된다.
- 사이드 이펙트(부수 효과)를 유발하는 코드를 함수 몸체(body) 안에 작성해서는 안 된다. => useEffect나 useCallback, useRef, useReducer같은 훅들을 사용하여 부수효과 관련 작업을 처리해야 함
- 동일 입력, 동일 출력을 지켜야 한다. (props(읽기 전용) → JSX 반환) => 컴포넌트의 일관성과 가독성, 예측가능성을 향상시키기 위한 것으로, 컴포넌트가 렌더링에 사용되는 입력(props, state, context)을 변경해서는 안 된다.
- StrictMode 컴포넌트의 역할은 계산이 순수한지 확인하는 것이다. (2번씩 렌더링)
- StrictMode는 배포(production) 모드에서 제거되므로 성능에 영향을 주지 않는다.
- 로컬 뮤테이션은 컴포넌트 함수 내부에서 이뤄져도 문제가 되지 않는다. => 함수 내부에서 사용되는 변수나 상태를 변경하는 것은 허용되지만, 외부에서 참조되는 변수나 상태 변경시 순수성이 깨질 수 있다. 화면을 업데이트 하려면 기존 객체를 변경하는 대신 상태(State)를 설정해야 한다.
// 로컬 뮤테이션: 컴포넌트 함수 내부에서만 사용되고 변경되는 변수나 상태를 의미하며, 외부에서 참조되지 않고 함수 내부 로직에만 영향을 주는 경우로 다음과 같은 경우에 사용된다.
- 반복문 내에서 인덱스 변수를 변경하는 경우
- 함수 내에서 임시 변수하고 변경하여 값을 계산하는 경우
- 배열이나 객체를 함수 내부에서 만들고 내부 로직에 따라 조작한 후 반환하는 경우