React学习笔记1——评论框的实现

学习链接:http://reactjs.cn/react/docs/tutorial-zh-CN.html

实现功能:主要分两个部分:1、评论列表的展示 2、评论框的输入提交

一、组件

1、拆分组件

一个大容器CommentBox中包含CommetList和CommetForm,CommetList中又包含多个Commet组件

2、CommentBox组件

var CommentBox = React.createClass({
    render: function(){
    return(
      <div>
        <CommentList />
        <CommentForm />
      </div>
    )
  }
})
ReactDOM.render({
  <CommetBox />,
  document.getElementById('content')
})
//首先在CommentBox中添加两个组件,然后将CommetBox渲染到页面上
  1. React组件必须用大写字母开头,且标签必须闭合,通过return函数返回的标签也必须是闭合的。比如我将<CommentList/>和<CommentForm/>外面的div去掉,就会报错
  2. React.createClass 是ES5形式的定义组件;后面又有了React.Component ,ES6形式的定义组件。(React定义组件的方法http://www.cnblogs.com/wonyun/p/5930333.html)
  3. ReactDOM.render({element, container, callback})渲染组件的方法,接收三个参数element 要渲染的组件,container渲染的组件要插入在DOM中的位置,callback回调函数,可选参数,传入时会在组件渲染完成后调用
  4. render React生命周期中的初始化阶段的一个函数,用来组装组件的html结构,必须要有返回值,返回的也可以是null 或者false

3、CommentList组件

var CommetList= React.createClass({
    render: function(){
    return(
      <div>    //包含多个comment组件
        <Comment />
        <Comment />
      </div>
    )
  }
})

4、Comment组件

var Comment = React.createClass({
    render: function(){
    return(
      <div>    
        <h3>"this is author"</h3>    //展示作者
        <div>"this is comment text"</div>    //展示评论       </div>     )   } })

5、CommentForm组件

var CommentForm = React.createClass({
    render: function(){
    return(
      <form>         <input type='text' placeholder='enter your name'/>
        <input type='text' placeholder='say something ...'/>
        <input type='submit' value='submit'/>
      </form>
           )   } })

二、数据

1、简介

React父子组件数据的传递可使用props和state。props属性是组件与生俱来的不可以由组件自己修改,state状态是事物自己的,可不断变化。主要区分是组件在运行时需要修改的是state,此外所有的数据都可以是props

  属性 状态
是否能从父组件获取初始值 T F
是否由父组件修改 T F
能否在组件内部设置默认值 T T
能否在组件内部修改 F T
能否设置子组件的初始值 T F
能否修改子组件的值 T F

(1)、this.props  用来访问从父组件传进来的数据

(2)、this.state  用来访问动态更新的数据

(3)、this.setState()  将服务器获取的数据更新到状态中(更新CommetList中的数据)

(4)、父子组件之间的数据通信,父组件通过this.props将数据传递给子组件;子组件通过委托(delegate)即事件处理函数与父组件通信,子组件触发函数,父组件处理。

2、获取、更新数据

ReactDOM.render( 
  <CommetBox url='/api/comments', pollInterval={2000}>,  //这个请求地址是在server中设置好了,
  document.getElementById('content')
)
var CommentBox = React.createClass({
  loadCommentsFromServer: function(){    
    $.ajax({
      url: this.props.url,     //通过this.props获取父组件中的属性
      dataType: 'json',
      cache: false,
      success: function(data){
        this.setState({data:data})        //动态更新的关键是通过this.setState()设置状态
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
 
   })
  },
  getInitialState:function(){
    return {data:[]}  
  },
  
  componentDidMount: function(){  
    this.loadCommentsFromServer();                      //这里通过设置定时器实时刷新数据,为了避免刚开始数据要在间隔时间后才出来的情况,所以先调用一次获取数据
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  render: function(){
    return(
      <div>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    )
  }
})
var CommentList = React.creatClass({
  render: function(){
    var commnetNodes = this.props.data.map(function(comment){  //data的数据结构[ {"author": "Pete Hunt", "text": "This is one comment"}, {"author": "Jordan Walke", "text": "This is *another* comment"} ]
      return(
        <Comment key={comment.id} author={comment.author}>
          {commnet.text}
        </Comment>
      )
    })
    return(
      <div>
        {commentNodes}
      </div>
    )
  }
})
var Comment = React.createClass({
  return(
    <div>
      <h3>
        {this.props.author}
      </h3>
      <p>
        {this.children.text.toString()}
      </p>
    </div>
  )
})

涉及到的生命周期:

(1)getInitialState 生命周期初始化阶段,初始化每个实例特有的状态,在生命周期里只执行一次,必须返回一个对象或者null

(2)componentDidMount 生命周期初始化阶段,在成功render并渲染完真实的DOM后react自动调用的方法,此时可以修改DOM。如果要在渲染后对DOM操作就是在这个阶段里。

三、事件

子组件通过事件与父组件通信,子组件触发,父组件处理。

1、添加评论,绑定事件

基本的操作在子组件CommentForm中完成

var CommentForm = React.createClass({
  getInitialState:function(){
    return({author:'',text:''})
  },
  handleAuthorChange: function(e){
    this.setState({author: e.target.value})    //通过this.setState()保证输入实时更新状态
  },
  handleTextChange: function(e){
    this.setState({text: e.target.value})
  },
  handleSubmit: function(e){            //提交事件,清空表单
    e.preventDefault();              //阻止提交表单的默认行为
    var author = this.state.author.trim();
    var text = this.state.text.trim();
    if (!author || !text) {
      return
    }
    this.setState({author:'',text:''})
  },
  
  render:function(){
    return(
      <form onSubmit={this.handleSubmit}>      //提交表单
      <input
        type='text'
        value={this.state.author}
        placeholder='your name'
        onChange = {this.handleAuthorChange}    //绑定事件
      />
      <input
        type='text'
        value={this.state.text}
        placeholder='enter something'
        onChange = {this.handleTextChange}         //绑定事件
      />
      <input type='submit' value='提交' />    
      </form>
      )
  }
})

2、提交更新评论  子组件传递数据给父组件

提交评论时需要刷新评论列表来包含这条评论。发送请求及刷新评论的操作在CommentBox(即父组件)中完成,原因是:CommentBox中有评论列表的状态。现在需要把CommentForm(子组件)中的数据传递到CommentBox(父组件)中,子组件通过事件与父组件通信。所以在父组件中传递一个回调函数(handleCommetSubmit)到子组件中,子组件绑定这个函数传值即可,这样只要子组件CommentForm中的事件被触发,父组件CommentBox中的回调函数handCommentSubmit就会被调用。

//CommentBox中
handleCommentSubmit: function(comment){ $.ajax({ url:this.props.url, dataType:'json', type:'POST', data: comment, success: function(data){ this.setState({data:data}) }.bind(this), error: function(xhr, status, err){ this.setState({data: comments}); console.log(this.props.url, status, err.toString()) }.bind(this) })
render: function(){
    return(
      <div>
        <CommentList data={this.state.data}/>
        <CommentForm onCommentSubmit={this.handleCommentSubmit}/> //传递回调函数给子组件
      </div>
      )
  }

//CommentForm中
  handleSubmit: function(e){
    e.preventDefault();
    var author = this.state.author.trim();
    var text = this.state.text.trim();
    if (!author || !text) {
      return
    }
    this.props.onCommentSubmit({author:author,text:text})    //绑定回调函数,则handleSubmit事件一触发,回调函数就会被调用
    this.setState({author:'',text:''})
  },

四、优化

 1、更新太慢要等请求完成后页面才会展示新的评论,手动添加新评论到列表中让体验更快一些

  handleCommentSubmit: function(comment) {
    var comments = this.state.data;
    comment.id = Date.now();
    var newComments = comments.concat([comment]);this.setState({data: newComments});
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      type: 'POST',
      data: comment,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        this.setState({data: comments});
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  }

2、插入的文本中如果有HTML标签,我们是默认展示成输入的样子的,如点<a href='.....'>这里</a>可以跳转哦。如果我们想要把这种样子的评论真正的渲染成HTML,可以用到dangerouslySetInnerHTML

<span dangerouslySetInnerHTML={{ __html: this.props.children.toString()}}/>
原文地址:https://www.cnblogs.com/xxchi/p/6678021.html