React进修笔记2:React官方CommentBox实践

新搭建的个人博客,本文地点:React进修笔记2:React官方CommentBox实践
一切的操纵是继承上一个进修笔记,参考的是React官方的CommentBox,不过不是100%根据其完成。
参考:https://facebook.github.io/re…

1、起首建立相干的文件

touch src/comment.js

2、修正webpack设置,一处是通知webpack预处理的实体增添comment.js,别的一个是通知webpack输出的时刻根据文件名字编译输出,而不是将一切js文件编译到bundle.js,[name]实际上是entry数组中的key,经由过程修正key可以归类目次,比方’comment/index’:./src/index.js,’comment/index’:’./src/comment.js’会将编译后的文件放到comment目次下,经由过程这些设置可以更好的构造代码构造

  entry:{
    'index':'./src/index.js',
    'comment':'./src/comment.js'
  },
  output: {
     path: path.resolve(__dirname, 'build'),
     filename: '[name].js'
  },

3、修正’build/index.html’引入文件修正为comment.js,从新运转webpack-dev-server,最先修正comment.js

<script src="comment.js"></script>

4、分拆Comment组件,梳理出以下构造,在React中一切的东西都是以组件的情势存在

- CommentBox
  - CommentList
    - Comment
  - CommentForm

5、建立CommentBox组件,return()中的类html内容,在react中叫做JSX语法,其自身相符XML语法,react在编译后会转化为响应的js文件,官方引见https://facebook.github.io/re…
以后可以去浏览器中看下结果

var CommentBox = React.createClass({
  render:function(){
    return (
      <div className='commentBox'>
          Hello world! I am a comment box.
      </div>
    )
  }
});
//衬着组件,注重修正index.html中div的id为content
ReactDOM.render(
  <CommentBox />,document.getElementById('content')
);

6、建立CommentList、CommentForm组件

var CommentList = React.createClass({
  render:function(){
    return (
      <div className='commentList'>
        Hello, I am a comment list!
      </div>
    )
  }
});

var CommentForm = React.createClass({
  render:function(){
    return (
      <div className='commentForm'>
        hi, I am a comment form.
      </div>
    )
  }
});

7、修正CommentBox代码,引入CommentList、CommentForm组件。下面代码中夹杂了HTML和组件代码,JSX编译器会自动将HTML代码用React.createElement(tagName)去转换。浏览器看下结果。

var CommentBox = React.createClass({
  render:function(){
    return (
      <div className='commentBox'>
        <h1>Comments</h1>
        <CommentList />
        <CommentForm />
      </div>
    )
  }
});

8、建立Comment组件,内里有{this.props.author}和{this.props.children}两个变量,称之为组件的属性。修正CommentList组件,可以看到我们通报了author属性。children是React预置属性,指向组件内嵌的内容。返回浏览器检察修正变化。

var Comment = React.createClass({
  render:function(){
    return (
      <div className='comment'>
        <h2 className='commentAuthor'>
          {this.props.author}
        </h2>
        {this.props.children}
      </div>

    )
  }
})
//修正CommentList组件,让其载入Comment组件
var CommentList = React.createClass({
  render:function(){
    return (
      <div className='commentList'>
        <Comment author='stone'>就是瞎比比</Comment>
        <Comment author='mpanda'>我不听瞎比比</Comment>
      </div>
    )
  }
});

9、增加Markdown支撑

//装置依靠包
npm install marked --save
//引入marked包
var marked = require('marked')
//修正Comment组件,应用marked组件剖析批评内容,转为富文本花样。运用toString()是为了明白传送给marked的为字符串花样。浏览器看结果结果
var Comment = React.createClass({
  render:function(){
    return (
      <div className='comment'>
        <h2 className='commentAuthor'>
          {this.props.author}
        </h2>
        {marked(this.props.children.toString())}
      </div>

    )
  }
})
//显现结果
Comments
stone
<p>就是瞎比比</p>
mpanda
<p>我不听瞎比比</p>
hi, I am a comment form.

10、剖析后的文本直接被显如今页面上,并没有被浏览器剖析,这是react为了防备被XSS进击而作的保护措施。React供应了一个并不友爱的特别API保证可以完成在浏览器显现原始HTML

var Comment = React.createClass({
  rawMarkup:function(){
    var rawMarkup = marked(this.props.children.toString(),{sanitize:true})
    return {__html:rawMarkup}
  },
  render:function(){
    return (
      <div className='comment'>
        <h2 className='commentAuthor'>
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={this.rawMarkup()} />
      </div>

    )
  }
})

JSX中dangerouslySetInnerHTML属性必需在接收到一个对象参数,且对象参数中明白运用__html作为key时,才会将其内容作为原始HTML插进去页面中,而且不发起直接在<div dangerouslySetInnerHTML={{__html:marked(this.props.children.toString(),{sanitize:true})}} />直接如许完成誊写,目标就是明白提示开发者,这里是有风险的,您是相对的信托这段插进去的内容。再次检察浏览器结果。It works!
11、批评数据明显应当来自效劳器,不过在动态猎取之前,我们先模仿一些数据

var data = [
  {"id":1,"author":"stone","text":"换一个位置瞎比比"},
  {"id":2,"author":"mpanda","text":"不喜欢你瞎比比"},
]
//通报数据到CommentBox
ReactDOM.render(
  <CommentBox data={data} />,document.getElementById('content')
);
//直接通报数据到CommentList
var CommentBox = React.createClass({
  render:function(){
    return (
      <div className='commentBox'>
        <h1>Comments</h1>
        <CommentList data={this.props.data} />
        <CommentForm />
      </div>
    )
  }
});
//在CommentList从新完成组件的组装,革新浏览器看结果
var CommentList = React.createClass({
  render:function(){
    var commentNodes = this.props.data.map(function(comment){
      return (
        <Comment author={comment.author} key={comment.id}>
          {comment.text}
        </Comment>
      )
    });
    return (
      <div className='commentList'>
        {commentNodes}
      </div>
    )
  }
});

12、从组件封装来讲我们已封装了一个很不错的组件,只须要通报相干json数据到CommentBox即可。不过一切的数据都是在组件建立的时刻,应用不可变量参数props一次性通报给组件。state一样为组件的私有变量,可以经由过程this.setState()来设置变量的值,每次设置变量的值,组件都邑从新衬着一遍本身。应用state修正我们的顺序,让其动态衬着页面。

//为了轻易举行ajax要求,引入jquery,固然完全可以不引入
var $ = require("jquery")
var CommentBox = React.createClass({
  //getInitialState函数在组件的全部生命周期只会实行一次,我们在内里初始化数据
  getInitialState:function(){
    return {data:[]}
  },
  //componentDidMount函数一样是有React自动挪用,时候是在组件第一衬着终了后。固然由于data在初始化的时刻数据为空,实际上这时刻衬着的组件没有内容。
  componentDidMount:function(){
    $.ajax({
      url:this.props.url,
      //因我当地server是php,且跨域,所以我们运用jsonp处理跨域题目,详细jsonp完成,请自行google
      dataType:"jsonp",
      cache:false,
      jsonp:'callback',
      jsonpCallback:'getComment',
      success:function(data){
        //猎取到数据后,经由过程setState设置数据,组件会自动再次衬着
        this.setState({"data":data})
      }.bind(this),
      error:function(xhr,status,err){
        console.log(this.props.url,status,err.toString())
      }.bind(this)
    })
  },
  render:function(){
    return (
      <div className='commentBox'>
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    )
  }
});
//将URL地点通报个组件
ReactDOM.render(
  <CommentBox url="http://***.local.com/" />,document.getElementById('content')
);

13、我们在浏览器看结果的时刻由于数据要求都是在毫秒级别完成不轻易看到从新衬着的结果,我们引入一个定时器。革新浏览器,哈哈,2s后自动载入了批评数据。

var CommentBox = React.createClass({
  getInitialState:function(){
    return {data:[]}
  },
  loadCommentsFromServer:function(){
    $.ajax({
      url:this.props.url,
      dataType:"jsonp",
      cache:false,
      jsonp:'callback',
      jsonpCallback:'getComment',
      success:function(data){
        this.setState({"data":data})
      }.bind(this),
      error:function(xhr,status,err){
        console.log(this.props.url,status,err.toString())
      }.bind(this)
    })
  },
  componentDidMount:function(){
    setInterval(this.loadCommentsFromServer,2000)
  },
  render:function(){
    return (
      <div className='commentBox'>
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    )
  }
});

14、官方教程中批评提交分两种完成。第一种完成了提交完成后,须要革新,再次从效劳器猎取批评数据,第二种提交批评后直接把提交的数据附加到批评背面,应用setState从新衬着页面。明显第二种体验更好,直接完成第二种。
先做剖析,在CommentForm组件中,假如完成数据的提交,那末须要从新设置CommentList中的数据,然则CommentList的数据又是CommentBox通报过去的,那末提交数据的操纵不如直接在CommentBox中完成,然后应用setState从新设置CommentList的数据,CommentList完成自动革新。

//之前猎取批评接口应用的是jsonp,然则提交批评必需post要领,所以jsonp没法完成,然则有不能经由过程跨域操纵。webpack支撑proxy(代办)形式,可以把一部分接口直接转发到后端,修正webpack设置,请自行替代后端效劳。
    devServer:{
        contentBase:'./build',
        proxy:{
            "/api/*":{
                target:"http://***.local.com:80",
                host:"***.local.com",
                secure: false,
            },
            bypass: function(req, res, proxyOptions) {
                if (req.headers.accept.indexOf('html') !== -1) {
                    console.log('Skipping proxy for browser request.');
                    return '/index.html';
                }
            },
        }
    }
//注重通报的url,会自动转发到http://***.local.com:80/api/comment
ReactDOM.render(
  <CommentBox url="http://localhost:8080/api/comment" />,document.getElementById('content')
);
var CommentBox = React.createClass({
  //增添批评提交要领,背景效劳  
  handleSubmitComment:function(data){
    $.ajax({
      //请注重,背景接口我把批评和猎取批评放到了一同,只是提交体式格局不一样,一个是get,一个是post
      url:this.props.url,
      type:"POST",
      data:data,
      dataType:"json",
      cache:false,
      success:function(data){
        //测试接口直接返回了我提交的内容,所以可以直接附加数据,让CommentList自动革新
        this.setState({data:this.state.data.concat(data)});
      }.bind(this),
      error:function(xhr,status,err){
        console.log(this.props.url,status,err.toString())
      }.bind(this)
    })
  },
  render:function(){
    return (
      <div className='commentBox'>
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        //将批评提交接口通报个CommentForm组件
        <CommentForm onSubmitComment={this.handleSubmitComment} />
      </div>
    )
  }
});

var CommentForm = React.createClass({
  getInitialState:function() {
    return {author:"",text:""}
  },
  //完成数据的绑定,经由过程setState也能保证跟此数据相干的UI完成从新的衬着
  handleAuthorChange:function(event){
    this.setState({author:event.target.value})
  },
  handleTextChange:function(event){
    this.setState({text:event.target.value})
  },
  handleSubmit:function(event){
    //构造表单默许的submit提交
    event.preventDefault();
    var author = this.state.author.trim()
    var text = this.state.text.trim()
    if(!text||!author) {
      return;
    }
    //挪用CommentBox上的批评提交要领
    this.props.onSubmitComment({author:author,text:text});
    this.setState({author:"",text:""})
  },

  render:function(){
    return (
      <form className='commentForm' onSubmit={this.handleSubmit}>
        <input type='text' onChange={this.handleAuthorChange}
           placeholder='怎样称谓您呢?爷' value={this.state.author} />
         <input type='text' onChange={this.handleTextChange}
           placeholder='爷有什么见教?' value={this.state.text} />
         <input type='submit' value='提交' />
      </form>
    )
  }
});

到此全部示例联络完成!以后要完成用es6语法重构该项目。

    原文作者:StonePanda
    原文地址: https://segmentfault.com/a/1190000004350267
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞