ReactJS - Render Props: 초보자를 위한 친절한 가이드

안녕하세요, React 개발자 지망생 여러분! 오늘 우리는 "Render Props"라는 흥미로운 개념에 대해 배우겠습니다. 처음에는 무서워 보일 수 있지만, 이 튜토리얼이 끝나면 프로가 될 것을 약속해드립니다. 이 흥미로운 여정을 함께 시작해봅시다!

ReactJS - Render Props

Render Props는 무엇인가요?

자, 구체적인 내용으로 들어가기 전에 Render Props가 무엇인지 이해해보겠습니다. 마법의 상자가 무언가 멋진 일을 할 수 있지만, 그 내용을 어떻게 표시할지 결정하고 싶은 상상을 해보세요. 그게 바로 React에서 Render Props가 하는 일입니다!

Render Props는 React 컴포넌트 간 코드를 공유하는 기술로, 그 값이 함수인 prop을 사용합니다. 이를 통해 컴포넌트는 prop으로 주어진 함수를 호출하여 렌더링해야 할 React 엘리먼트를 알 수 있습니다.

간단한 예제를 보겠습니다:

class MagicBox extends React.Component {
render() {
return (
<div>
{this.props.render('Abracadabra!')}
</div>
)
}
}

// MagicBox 사용
<MagicBox render={(magic) => <h1>{magic}</h1>} />

이 예제에서 MagicBox는 우리의 컴포넌트이며, render prop을 가지고 있습니다. 이 render prop은 MagicBox가 어떤 데이터('Abracadabra!'인 경우)를 호출하여 렌더링해야 할지를 결정하는 함수입니다.

Render Props 사용법

이제 기본적인 이해를 얻었으므로, 더 실践적인 상황에서 Render Props를 어떻게 사용하는지 탐구해보겠습니다. 마우스 위치를 추적하는 컴포넌트를 만들어 보겠습니다 - Render Props를 보여주는 전형적인 예제입니다.

class MouseTracker extends React.Component {
state = { x: 0, y: 0 };

handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
}

render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}

// MouseTracker 사용
<MouseTracker
render={({ x, y }) => (
<h1>마우스 위치는 ({x}, {y})입니다</h1>
)}
/>

이를 간단히 설명하자면:

  1. MouseTracker 컴포넌트는 마우스 위치를 추적합니다.
  2. 마우스가 이동할 때마다 상태를 업데이트합니다.
  3. 렌더 메서드에서 render prop 함수를 호출하여 현재 상태를 전달합니다.
  4. MouseTracker를 사용할 때, 마우스 좌표를 받아서 렌더할 내용을 정의합니다.

이 접근 방식을 통해 마우스 추적 로직을 재사용하면서도 다양한 문맥에서 정보를 어떻게 표시할지 결정할 수 있습니다.

Render Props 적용

이제 기본적인 내용에 익숙해졌으므로, 더 복잡한 문제를 해결하기 위해 Render Props를 적용해보겠습니다. 다양한 유형의 데이터를 표시할 수 있는 데이터 가져오기 컴포넌트를 만들어 보겠습니다.

class DataFetcher extends React.Component {
state = { data: null, loading: true, error: null };

componentDidMount() {
this.fetchData();
}

fetchData = async () => {
try {
const response = await fetch(this.props.url);
const data = await response.json();
this.setState({ data, loading: false });
} catch (error) {
this.setState({ error, loading: false });
}
}

render() {
return this.props.render(this.state);
}
}

// 사용자 데이터를 위한 DataFetcher
<DataFetcher
url="https://api.example.com/user"
render={({ data, loading, error }) => {
if (loading) return <div>로딩 중...</div>;
if (error) return <div>에러: {error.message}</div>;
return <div>환영합니다, {data.name}!</div>;
}}
/>

// 제품 데이터를 위한 DataFetcher
<DataFetcher
url="https://api.example.com/products"
render={({ data, loading, error }) => {
if (loading) return <div>제품 로딩 중...</div>;
if (error) return <div>제품 로드 실패: {error.message}</div>;
return (
<ul>
{data.map(product => (
<li key={product.id}>{product.name}: ${product.price}</li>
))}
</ul>
);
}}
/>

이 예제에서 DataFetcher 컴포넌트는 데이터 가져오기 로직을 처리하며, Render Props를 통해 다양한 문맥에서 데이터(또는 로딩/에러 상태)를 어떻게 표시할지 결정할 수 있습니다.

Render Props 메서드

다음 표는 Render Props에서 자주 사용되는 메서드를 요약합니다:

메서드 설명
render 가장 일반적인 Render Props 함수 이름
children Render Props로 사용할 수 있으며, 자연스러운 JSX 중첩을 허용합니다
커스텀 이름 Render Props 함수에 대해 원하는 이름을 사용할 수 있습니다

결론

Render Props는 React에서 유연성과 코드 재사용을 가능하게 하는 강력한 패턴입니다. 로직과 표시를 분리함으로써 더 modular하고 유지보수 가능한 코드를 만들 수 있습니다.

하지만, Render Props는 항상 최고의 솔루션이 아닙니다. 때로는 더 간단한 패턴인 컴포지션 또는 Hooks가 더 적합할 수 있습니다. 경험을 쌓아가면서 각 패턴을 언제 사용해야 하는 직감을 개발하게 될 것입니다.

계속 연습하고, 호기심을 유지하고, 행복하게 코딩하세요! Render Props를 사용하여 다음 큰 React 라이브러리를 만들 수도 있을지도 모릅니다. 프로그래밍의 세계에서는 더 이상한 일이 벌어질 수 있습니다!

Credits: Image by storyset