-
리액트 주요개념 - 합성 vs 상속IT/리액트 2022. 1. 16. 20:34728x90
React는 강력한 합성 모델을 가지고 있으며, 상속 대신 합성을 사용하여 컴포넌트 간에 코드를 재사용하는 것이 좋습니다.
컴포넌트에서 다른 컴포넌트를 담기
어떤 컴포넌트들은 어떤 자식 엘리먼트가 들어올 지 미리 예상할 수 없는 경우가 많습니다. 특히 범용적인 박스 역할을 하는 Sidebar 또는 Dialog와 같은 컴포넌트에서 흔히 볼 수 있습니다.
이러한 컴포넌트에서는 특수한 children prop을 사용하여 자식 엘리먼트를 출력하여 그대로 전달하는 것이 좋습니다.
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ) }
이러한 방식으로 다른 컴포넌트에서 JSX를 중첩하여 임의의 자식을 전달할 수 있습니다.
function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); }
<FancyBorder> 태그 안에 있는 <h1>, <p>가 FancyBorder 컴포넌트의 children prop으로 전달됩니다. FancyBorder는 {props.children}을 <div>에 렌더링하므로 전달된 엘리먼트들이 최종 출력됩니다.
글자의 폰트/사이즈, 테두리 두께/색상은 css파일을 생성하고 지정하였습니다.
//composition.css 파일 .FancyBorder { padding: 5px 5px; border: 5px solid; } .FancyBorder-blue { border-color: blue; } .Dialog-title { margin: 0; font-family: sans-serif; } .Dialog-message { font-size: larger; }
생성한 css파일을 적용하기 위해서는 적용하려는 페이지의 js파일에 해당 css파일을 import 해줍니다.
import './Composition.css'
종종 컴포넌트에서 여러 개의 컴포넌트를 담고자하는 경우가 있습니다. 이런 경우 children 대신 자신만의 고유한 방식을 적용할 수 있습니다.
// Composition.js function Contacts() { return <div className="Contacts" />; } function Chat() { return <div className="Chat" />; } function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ) } function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); } function Composition() { return ( <div> <App /> </div> ); }
<Contacts />와 <Chat />같은 React 엘리먼트는 객체이기 때문에 다른 데이터처럼 prop로 전달할 수 있습니다. React에서 prop으로 전달할 수 있는 것에는 제한이 없습니다.
// Composition.css .SplitPane { width: 100%; height: 100px; } .SplitPane-left { float: left; width: 30%; height: 100%; } .SplitPane-right { float: left; width: 70%; height: 100%; } .Contacts { width: 100%; height: 100%; background: lightblue; } .Chat { width: 100%; height: 100%; background: pink; }
특수화
때로 어떤 컴포넌트의 특수한 경우인 컴포넌트를 고려해야 하는 경우가 있습니다.
예) WelcomeDialog는 Dialog의 특수한 경우라고 할 수 있습니다.
React에서는 합성을 통해 해결할 수 있습니다. 더 구체적인 컴포넌트가 일반적인 컴포넌트를 렌더링하고 props를 통해 내용을 구성합니다.
// 일반적인 컴포넌트 function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> </FancyBorder> ) } // 구체적인 컴포넌트 function WelcomeDialog() { return ( <Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> ); }
합성은 클래스로 정의된 컴포넌트에서도 동일하게 적용됩니다.
function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> {props.children} </FancyBorder> ) } class SignUpDialog extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.handleSignUp = this.handleSignUp.bind(this); this.state = {login: ''}; } handleChange(e) { this.setState({login: e.target.value}); } handleSignUp() { alert(`Welcome aboard, ${this.state.login}!`); } render() { return ( <Dialog title="Mars Exploration Program" message="How should we refer to you?"> <input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}> Sign Me Up! </button> </Dialog> ); } }
그렇다면 상속은?
Facebook에서는 수천 개의 React 컴포넌트를 사용하지만 컴포넌트를 상속 계층 구조로 작성을 권장할만한 사례를 아직 찾지 못했다고 합니다.
props와 합성은 명시적이고 안전한 방법으로 컴포넌트의 모양과 동작을 커스터마이징하는데 필요한 모든 유연성을 제공합니다. 컴포넌트가 원시 타입의 값, React 엘리먼트 혹은 함수 등 어떠한 props도 받을 수 있습니다!!
UI가 아닌 기능을 여러 컴포넌트에서 재사용하기를 원한다면 별도의 JavaScript 모듈로 분리하는 것이 좋습니다. 컴포넌트에서 해당 함수, 객체, 클래스 등을 import 하여 사용할 수 있습니다. ==> 상속 받을 필요가 없다!
728x90'IT > 리액트' 카테고리의 다른 글
리덕스란? (0) 2022.08.16 리액트 주요개념 - React로 사고하기 (0) 2022.01.16 리액트 주요개념 - State 끌어올리기 (0) 2022.01.16 리액트 주요개념 - 폼 (0) 2022.01.16 리액트 주요개념 - 리스트와 key (0) 2022.01.16