render props 패턴으로 구현된 컴포넌트는 자체적으로 렌더링 로직을 구현하는 대신, react 엘리먼트 요소를 반환하는 함수를 props로 전달합니다.
Mouse컴포넌트는 마우스 위치를 추적하는 로직을 캡슐화 한 것이고, MouseTracker컴포넌트는 이 Mouse컴포넌트를 가져와 렌더링하는 로직입니다.
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY,
});
}
render() {
return (
<div style={{ height: "100vh" }} onMouseMove={this.handleMouseMove}>
<p>
The current mouse position is ({this.state.x}, {this.state.y})
</p>
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<>
<h1>Move the mouse around!</h1>
<Mouse />
</>
);
}
}
마우스 주위에 고양이 그림을 보여주려면 고양이 그림을 렌더링하는 Cat.jsx 컴포넌트를 만들고 MouseWithCat컴포넌트에 렌더링합니다.
그리고 MouseWithCat컴포넌트를 MouseTracker컴포넌트에 렌더링합니다.
import React from "react";
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return <img src="/cat.jpg" style={{ position: "absolute", left: mouse.x, top: mouse.y }} />;
}
}
class MouseWithCat extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY,
});
}
render() {
return (
<div style={{ height: "100vh" }} onMouseMove={this.handleMouseMove}>
<Cat mouse={this.state} />
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<MouseWithCat />
</div>
);
}
}
그러나 이 경우 Mouse 컴포넌트를 사용할 때 마다 별도의 MouseWithSomethingElse 컴포넌트를 만들어야 합니다, 그러므로 MouseWithCat는 아직 정말로 재사용이 가능한게 아닙니다.
🌟여기에 render prop를 사용할 수 있습니다. Mouse 컴포넌트 안에 Cat 컴포넌트를 하드 코딩(hard-coding)해서 결과물을 바꾸는 대신에,
Mouse에게 동적으로 렌더링할 수 있도록 해주는 함수 prop을 제공하는 것입니다.
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse render={(mouse) => <Cat mouse={mouse} />} />
</div>
);
}
} // MouseTracker는 Mouse컴포넌트에 Cat컴포넌트를 반환하는 함수를 render props로 전달합니다.
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.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>
);
} //<Mouse>가 무엇을 렌더링하는지에 대해 명확히 코드로 표기하는 대신,
} //`render` prop을 사용하여 무엇을 렌더링할지 동적으로 결정할 수 있습니다.
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return <img src="/cat.jpg" style={{ position: "absolute", left: mouse.x, top: mouse.y }} />;
}
}
✅ 정리하자면, render prop은 무엇을 렌더링할지 컴포넌트에 알려주는 함수입니다.
✔ prop name으로 render를 사용할 필요는 없습니다. 사실, 어떤 함수형 prop이든 render prop이 될 수 있습니다.
<Mouse children={mouse => (//props name으로 꼭 render를 사용할 필요는 없습니다.
<p>The mouse position is {mouse.x}, {mouse.y}</p>
)}/>
✔ 혹은, 어트리뷰트 이름을 지정해줄 필요 없이, element 안에 직접 꽂아넣을 수 있습니다!
<Mouse>
{mouse => (
<p>The mouse position is {mouse.x}, {mouse.y}</p>
)}
</Mouse>
이 테크닉은 자주 사용되지 않기 때문에, API를 디자인할 때 children은 함수 타입을 가지도록 propTypes를 지정하는 것이 좋습니다.
Mouse.propTypes = {
children: PropTypes.func.isRequired
};
render props 패턴을 사용하면 React.PureComponent를 사용할 때 발생하는 이점이 사라질 수 있습니다.
class Mouse extends React.PureComponent {
// 위와 같은 구현체...
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
이 예시에서 MouseTracker가 render 될때마다, <Mouse render>
의 prop으로 넘어가는 함수가 계속 새로 생성됩니다. 따라서 Mouse 컴포넌트가 React.PureComponent를 상속받은 효과가 사라지게 됩니다.
class MouseTracker extends React.Component {
// `this.renderTheCat`를 항상 생성하는 매서드를 정의합니다.
// 이것은 render를 사용할 때 마다 *같은* 함수를 참조합니다.
renderTheCat(mouse) {
return <Cat mouse={mouse} />;
}
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<Mouse render={this.renderTheCat} />
</div>
);
}
}
StrictMode는 애플리케이션 내의 잠재적인 문제를 알아내기 위한 도구입니다.
function ExampleApplication() {
return (
<div>
<Header />
<React.StrictMode> //strictMode 태그로 감싼 컴포넌트만 strice모드가 활성화됩니다.
<div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode>
<Footer />
</div>
);
}
strictMode는 다음과 같은 오류를 잡아냅니다