React实践(一)

React组件实践

最近在学习React,上一篇写了自己React入门的一些笔记。组件component作为React的主要特性,于是作为自己的实践开发了评论组件,一般上是需要与后台交互,但为了简便就省了这一步,而直接在页面造了假数据进行测试。

组件结构

|– CommentBox
|– CommentList
|– Comment
|– Pagination
|– CommentForm

Comment子组件

该组件相对简单,作为每条评论的UI显示,包括用户名和评论。所以只需使用render()方法即可。

1
var Comment = React.createClass({
  render: function() {
    return (
      <div className="list-group-item">
        <div className="row-action-primary">
            <i className="mdi-file-folder"></i>
        </div>
        <div className="row-content">
          <h4 className="list-group-item-heading">{this.props.username}</h4>
          <p className="list-group-item-text">{this.props.comment}</p>
        </div>
      </div>
    );
  }
});

用户名和评论分别使用组件的参数this.props.usernamethis.props.comment传递。

Pagination子组件

该组件用于评论列表的分页,以curPage当前页作为组件的状态state,每次该值的更新,更新组件的UI显示,并调用父组件CommentListchangePage()方法更新评论列表。

1
var Pagination = React.createClass({
  getInitialState: function() {
    return {
      curPage: 1
    }
  },
  handlePageChange: function(num,e) {
    e.preventDefault();
    var curPage = this.state.curPage;
    var total = this.props.total;
    if(num=='pre') {
      num = curPage == 1? curPage: curPage - 1;
    }
    else if(num == 'next') {
      num = curPage == total? curPage: curPage + 1;
    }
    this.setState({curPage:num});
    this.props.changePage(num);
  },
  render: function() {
    var total = this.props.total;
    var page = Array.apply(null,{length:total}).map(function(i,index){return index+1});
    var curPage = this.state.curPage;
    var _this =this;
    return(
      <ul className="pagination pagination-sm">
        <li className={curPage==1?"disabled":""}><a href="#" onClick={_this.handlePageChange.bind(null,'pre')}>«</a></li>
      {
        page.map(function(i) {
          //这是的this指向窗口
          return (
            <li className={curPage==i?"active":""}>
              <a href="#" onClick={_this.handlePageChange.bind(null,i)}>{i}</a>
            </li>
          )
        })
      }
        <li><a href="#" onClick={_this.handlePageChange.bind(null,'next')}>»<div className={curPage==total?"disabled":"ripple-wrapper"}></div></a></li>
      </ul>
    )
  }
});

render()方法中根据页数(total组件参数)显示页码。当前页码使用className={curPage==i?"active":""}自动更新样式。

有点要注意,在map()方法回调函数中this指向的是window当前窗口。而a链接标签click事件onClick={_this.handlePageChange.bind(null,i)}使用bind方法可向事件处理函数传递参数。

事件处理中需调用this.setState()更新组件的状态,随后调用父组件的方法更新评论列表。

CommentList组件

评论列表组件,以curPage当前页作为组件的状态state

1
var CommentList = React.createClass({
  getInitialState: function(){
    return {
      curPage: 1
    };
  },
  getDefaultProps: function() {
    return {
      count: 5
    };
  },
  handlePageChange: function(num) {
    this.setState({curPage: num})
  },
  render: function() {
    var curPage = this.state.curPage;
    var count = this.props.count;
    var list = this.props.list.slice((curPage - 1) * count, count * curPage);
    var total = Math.ceil(this.props.list.length / count)
    return (
      <div className="list-group">
      {
        list.map(function(item){
          return (
            <div>
              <Comment username={item.name} comment={item.comment} />
              <div className="list-group-separator"></div>
            </div>
          );
        })
      }
      <Pagination total={total} changePage={this.handlePageChange} />
      </div>
    )
  }
});

CommentForm组件

评论表单组件,提交表单调用父组件方法this.props.onHandleSubmit()更新评论列表。

1
var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var usernameInput = React.findDOMNode(this.refs.usernameInput);
    var commentInput = React.findDOMNode(this.refs.commentInput);
    var data = {
      name: usernameInput.value,
      comment: commentInput.value
    }
    if(data.name.trim() == '' || data.comment.trim()=='')
      return;
    this.props.onHandleSubmit(data);
    usernameInput.value='';
    commentInput.value=''
    return ;
  },
  render: function() {
    return (
      <form className="form-horizontal" onSubmit={this.handleSubmit}>
        <fieldset>
          <legend>我要评论</legend>
          <div className="form-group">
            <div className="form-control-wrapper">
              <input className="form-control empty" ref="usernameInput" id="focusedInput" type="text" />
              <div className="floating-label">用户名</div>
            </div>
          </div>
          <div className="form-group">
            <div className="form-control-wrapper">
              <textarea className="form-control empty" ref="commentInput" rows="3" id="textArea"></textarea>
              <div className="floating-label">评论</div>
            </div>
          </div>
          
          <div className="form-group">
              <div className="col-lg-10 col-lg-offset-2">
                  <button className="btn btn-default">Cancel</button>
                  <button type="submit"  className="btn btn-primary">Submit</button>
              </div>
          </div>
        </fieldset>
      </form>
    )
  }
});

CommentBox组件

以评论列表数据list作为组件的状态,更新时将CommentForm提交的评论添加到list的头部。

1
var CommentBox = React.createClass({
  getInitialState: function() {
      return {list:this.props.list};
  },
  updateList: function(data) {
    var list = this.state.list;
    list.unshift(data);
    this.setState({list:list})
  },
  render: function() {
    return (
      <div>
        <CommentList list={this.state.list} {...this.props}/>
        <CommentForm onHandleSubmit={this.updateList}/>
      </div>
    )
  }
})

使用CommentBox组件

1
// 测试数据
var commentList = [
  {name:'user1',comment: 'hello world1'},
  {name:'user2',comment: 'hello world2'},
  {name:'user3',comment: 'hello world3'},
  {name:'user4',comment: 'hello world4'},
  {name:'user5',comment: 'hello world1'},
  {name:'user6',comment: 'hello world2'},
  {name:'user7',comment: 'hello world3'},
  {name:'user8',comment: 'hello world4'},
  {name:'user9',comment: 'hello world1'},
  {name:'user10',comment: 'hello world2'},
  {name:'user11',comment: 'hello world3'},
  {name:'user12',comment: 'hello world4'},
  {name:'user13',comment: 'hello world3'},
  {name:'user14',comment: 'hello world4'},
];

React.render(
  <CommentBox list={commentList} count={10}/>,
  document.getElementById('commentBox')
)