React 체험
Dev

React 체험

2015. 12. 18. 01:27

이전에 AngularJS를 쓰느냐 Handlebars를 쓰느냐 고민을 하면서 댓글 리스트 샘플을 만들어봤었는데 뒤늦게 React로도 한번 만들어봤다. 마침 튜토리얼도 댓글이라 튜토리얼을 많이 참고했다.

사실 다들 React, React 해서 진작에 살펴봤어야 했는데 이제야 React에 관심을 가지는 이유는 그간 React 방식이 그닥 맘에 들지 않았기 때문이다. javascript로 XML을 통해 dom을 컨트롤하는 것이 특히 그랬다. 그것을 JSX라고 한다. 그리고 AngularJS 에도 제법 익숙해졌기 때문이기도 하다.

준비

<script src="https://fb.me/react-0.14.3.min.js"></script>
<script src="https://fb.me/react-dom-0.14.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script type="text/babel" src="/js/react/comment.js"></script>

실제 필요한 것은 react, react-dom, compile된 comment.js 인데 개발환경이기에 babel을 포함하고 comment.js의 type을 text/babel로 설정했다.

댓글 구조

- CommentBox
	- CommentList
		- Comment
	- CommentForm

React는 커스텀 태그를 통해서 render를 시작한다. 그래서 댓글 구조를 먼저 만들 필요가 있다. 그닥 달라질 것이 없기에 튜토리얼에서 사용하는 구조를 그대로 사용했다.

ReactDOM

ReactDOM.render(
  <CommentBox />,
  document.getElementById('content')
);

처음 시작점은 ReactDOM 이다. contentCommentBox를 render해서 안에 넣는다.

CommentBox

var CommentBox = React.createClass({
	getInitialState: function() {
		return {
			count: sample.count,
			data: sample.list
		};
	},
	handleCommentSubmit: function(comment) {
		this.setState({
			count: this.state.count + 1,
			data: this.state.data.concat(comment)
		});
	},
	handleMoreList: function() {
		this.setState({
			data: sample.olderList.concat(this.state.data)
		});
	},
	render: function() {
		return (
			<div className="commentBox">
				<h3>Comments {this.state.count}</h3>
				<CommentList data={this.state.data} count={this.state.count} onClickMoreList={this.handleMoreList} />
				<CommentForm onCommentSubmit={this.handleCommentSubmit} />
			</div>
		);
	}
});

React에서 사용하는 dom은 같은 이름의 변수로 만든다. CommentBox라는 이름의 React Class를 만들고 CommentListCommentForm을 render 하도록 한다. 튜토리얼에서는 먼저 간단히 동작하는 코드를 만들고 차근차근 살을 붙여나가는데 이 코드는 모든 액션이 들어가 있어서 조금 길다.

댓글 데이터는 state 로 관리하고 댓글폼에서 submit이 발생했을 때나 댓글 더보기를 했을 때에 대한 handler 정도가 있다. JSX에 property들을 설정했는데 각 클래스 내부에서 this.props.NAME 으로 접근하면 된다.

CommentList

var CommentList = React.createClass({
    handleMoreList: function(e) {
        this.props.onClickMoreList();
    },
    render: function() {
        var commentNodes = this.props.data.map(function(comment) {
            var commentDate = timeStampToDate(comment.date);
            return (
                <Comment author={comment.author.name} thumbnail={comment.author.image} date={commentDate}>
                    {comment.message}
                </Comment>
            )
        });
        var btnMore = this.props.data.length < this.props.count? <button className="btn_comment_more" style={{display:'block'}} onClick={this.handleMoreList}>이전댓글 더보기</button>:'';
        return (
            <div className="comment_list">
                {btnMore}
                <ul id="comment-list">
                    {commentNodes}
                </ul>
            </div>
        );
    }
});

var Comment = React.createClass({
  render: function() {
    return (
      <li className="animation_up">
          <div className="comment_profile">
              <img src={this.props.thumbnail} />
          </div>
          <div className="comment_content">
              <div>{this.props.author} {this.props.date}</div>
              <div>{this.props.children}</div>
          </div>
      </li>
    );
  }
});

댓글 리스트는 Comment의 리스트를 가지고 있다. 이는 render 내부의 변수명을 치환자로 사용해서 만든다. 더보기 버튼도 마찬가지다. JSX 내부에서 사용하는 치환자 {NAME}는 동일한 이름의 변수 var NAME를 만들어주면 된다.

CommentForm

var CommentForm = React.createClass({
    getInitialState: function() {
        return {
            message: ''
        };
    },
    handleTextChange: function(e) {
        this.setState({message: e.target.value});
    },
    handleSubmit: function(e) {
        e.preventDefault();
        this.props.onCommentSubmit({author: sample.author, date: new Date(), message: this.state.message});
        this.setState({message: ''});
    },
    render: function() {
        return (
            <div className="comment_form">
                <form className="form" onSubmit={this.handleSubmit}>
                    <div className="form-group">
                        <label>Message</label>
                        <input type="text" className="form-control" value={this.state.message} onChange={this.handleTextChange} />
                    </div>
                    <div className="form-group">
                        <button className="btn btn-primary" type="submit">저장</button>
                    </div>
                </form>
            </div>
        );
    }
});

튜토리얼에서는 수정도 있고 ajax 통신도 있는데 간단한 예제라서 그런 부분은 없다보니 좀 별게 없다. form을 만들고 submit을 처리를 한다. submit할때 실제 폼 액션을 사용하면 안되니 내부에서 e.preventDefault()를 호출해야 한다.

마치며

처음에 JSX를 쓰는건 조금 어색했지만 점점 눈과 손에 익숙해지니 의외로 편하고 쉽게 느껴졌다. 특히 각 부분을 class화해서 재사용이 가능한 부분과 각 class간 통신을 프로퍼티로 정의해서 interface처럼 만드는 것은 굉장히 맘에 들었다. 그리고 튜토리얼 문서가 너무 좋았다. 토비의 스프링을 읽으며 스프링을 공부할때 느낀 자상함을 이 문서에서도 느낄 수 있었다.

아직 React로 뭔가를 만들어본 적은 없지만 밑바닥부터 뭔가를 만들어야 할 일이 생긴다면 React를 써보고 싶다. 어차피 class 만들고 이벤트 처리 만들고 하다보면 비슷한 구조를 만들게 될 것 같은데 그럴거라면 React를 사용하지 않을 이유가 없을 것 같다.

참조


반응형