티스토리 뷰

React.JS

[React.JS] Composition VS Inheritance

버미노트 2017. 4. 25. 13:31

React.JS

React는 강력한 Composition model을 가지고 있기 때문에, 상속(Inheritance) 대신에 조합(Composition)을 사용하는 것이 좋습니다. 이번 포스트에서 React의 Composition을 이야기 하기 위해 간단한 Dialog 예제를 만들어 보겠습니다.

참고

- IS A 형태의 상속(Inheriance)

class String extends Object {
  // 메소드 ...
}

위의 String 클래스와 Object 클래스의 관계를 보면, String IS A Object 관계가 됩니다. 위와 같이 IS A 관계 일 때 Inheritance를 사용해야 합니다.

- HAS A 형태의 조합(Composition)

class BurgerSet {
  Burger name;
}

위의 BurgetSet 클래스와 Burger 클래스의 관계를 보면, BurgerSet HAS A Burger 관계가 됩니다. 위와 같이 HAS A 관계 일 때 Composition을 사용해야 합니다.

1. Dialog 컴포넌트

일부 컴포넌트는 자신의 child element가 무엇이 올지 알지 못합니다. Dialog와 같이, Dialog가 출력 될 때 매번 Dialog의 내용이 달라지기 때문에 Dialog 컴포넌트는 자신의 child element가 무엇이 올지 알지 못합니다. 이럴 때, children을 직접 출력할 수 있도록 전달해 주는 것이 좋습니다.

props.children을 이용하여 children을 출력할 수 있습니다.

class Dialog extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="confirm-dialog">
        <h1>{this.props.title}</h1>
        <p>{this.props.contents}</p>
        {this.props.children}
      </div>
    );
  }
}
  • 8번 줄, 부모 컴포넌트에서 전달 받은 title을 출력합니다.
  • 9번 줄, 부모 컴포넌트에서 전달 받은 contents를 출력합니다.
  • 10번 줄, props.children으로 하위 element를 전달 받아 직접 출력합니다.

2. AlertDialog 컴포넌트

AlertDialog 컴포넌트는 Dialog를 포함(Containment)하여 조립(Composition)되어진 컴포넌트입니다.

class AlertDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleCancel = this.handleCancel.bind(this);
  }

  handleCancel(event) {
    alert("Alert CANCEL");
  }

  render() {
    return (
      <Dialog
        title={this.props.title}
        contents={this.props.contents}>
        <button onClick={this.handleCancel}>취소</button>
      </Dialog>
    );
  }
}
  • 14번 줄, Dialog 컴포넌트의 타이틀로 표시될 값을 전달합니다.
  • 15번 줄, Dialog 컴포넌트의 내용으로 표시될 값을 전달합니다.
  • 16번 줄, 취소 버튼을 클릭시 실행될 이벤트 핸들러를 등록합니다.

3. ConfirmDialog 컴포넌트

AlertDialog 컴포넌트와 동일하게 Dialog를 포함(Containment)하여 조립(Composition)되어진 컴포넌트입니다. AlertDialog와 다른 점은 ConfirmDialog는 확인과 취소로 버튼이 두개가 있다는 점입니다.

class ConfirmDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleCancel = this.handleCancel.bind(this);
    this.handleConfirm = this.handleConfirm.bind(this);
  }

  handleCancel(event) {
    alert("Confirm CANCEL");
  }

  handleConfirm(event) {
    alert("Confirm OKAY");
  }

  render() {
    return (
      <Dialog
        title={this.props.title}
        contents={this.props.contents}>
        <button onClick={this.handleCancel}>취소</button>
        <button onClick={this.handleConfirm}>확인</button>
      </Dialog>
    );
  }
}
  • 19번 줄, Dialog 컴포넌트의 타이틀로 표시될 값을 전달합니다.
  • 20번 줄, Dialog 컴포넌트의 내용으로 표시될 값을 전달합니다.
  • 21번 줄, 취소 버튼을 클릭시 실핼될 이벤트 핸들러를 등록합니다.
  • 22번 줄, 확인 버튼을 클릭시 실행될 이벤트 핸들러를 등록합니다.

4. DialogTest 컴포넌트

Dialog를 보이기 위해 타이틀과 내용, dialog 종류를 선택 할 수 있는 DialogTest 컴포넌트를 만들었습니다.
DialogTest 컴포넌트도, AlertDialog 컴포넌트와 ConfirmDialog 컴포넌트를 포함하여 조립한 컴포넌트가 되겠죠?

class DialogTest extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      title: "",
      contents: "",
      dialogType: ""
    };
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }

  handleInputChange(event) {
    var name = event.target.name;
    this.setState({
      [name]: event.target.value,
      dialogType: ""
    });
  }

  handleClick(event) {
    var name = event.target.name;
    this.setState({
      dialogType: name
    });
  }

  render() {
    var title = this.state.title;
    var contents = this.state.contents;
    var dialogType = this.state.dialogType;

    var popup = null;
    if (dialogType == "confirm") {
      popup = (
        <ConfirmDialog
          title={title}
          contents={contents}>
        </ConfirmDialog>
      )
    } else if (dialogType == "alert") {
      popup = (
        <AlertDialog
          title={title}
          contents={contents}>
        </AlertDialog>
      )
    }

    return(
      <div>
        title: <input value={title} name="title" onChange={this.handleInputChange} /><br />
        contents: <input value={contents} name="contents" onChange={this.handleInputChange} /><br />
        <button name="confirm" onClick={this.handleClick}>Confirm</button>
        <button name="alert" onClick={this.handleClick}>Alert</button>
        <br />
        <br />
        {popup}
      </div>
    )
  }
}
  • 4~8번 줄, Dialog의 종류와 타이틀, 내용을 저장하기 위한 state를 초기화 합니다.
  • 13~19번 줄, input 값이 변경될 경우 실행되는 이벤트 핸들러입니다. 계산되어진 변수 이름을 사용하여, title과 contents를 저장합니다.
    ([React.JS] Forms 참고)
  • 21~26번 줄, 버튼이 click 될 경우 실행되는 이벤트 핸들러입니다. 이 핸들러도 마찬가지로 계싼되어진 변수 이름을 사용하였습니다.
  • 33~48번 줄, 클릭된 버튼의 종류에 따라 출력할 Dialog를 생성합니다.
  • 58번 줄, 33~48번 줄에서 생성된 Dialog를 출력합니다.

5. 결과

CodePen으로 예제 확인하기

위의 코드 구조는 아래 그림과 같습니다.

Dialog
Dialog

참고

'React.JS' 카테고리의 다른 글

[React.JS] Redux 소개  (0) 2017.05.03
[React.JS] 리액트 라우터(react-router v4)  (2) 2017.04.28
[React.JS] Lifting State Up  (0) 2017.04.24
[React.JS] Forms  (0) 2017.04.22
[React.JS] List와 Key  (0) 2017.04.18
댓글
공지사항
최근에 올라온 글