<p><code></p> <p>新搭建的个人博客,本文地址:<a href="http://www.j2do.com/blog/post/React%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B02%EF%BC%9AReact%E5%AE%98%E6%96%B9CommentBox%E5%AE%9E%E8%B7%B5" rel="nofollow noreferrer" target="_blank">React学习笔记2:React官方CommentBox实践</a><br />所有的操作是继续上一个学习笔记,参考的是<a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a>官方的CommentBox,不过不是100%按照其实现。<br />参考:<a href="https://facebook.github.io/react/docs/tutorial.html" rel="nofollow noreferrer" target="_blank">https://facebook.github.io/re...</a></p> <p>1、首先创建相关的文件</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="touch src/comment.js" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs nginx"><code style="word-break: break-word; white-space: initial;"><span class="hljs-attribute">touch</span> src/comment.js</code></pre> <p>2、修改webpack配置,一处是告诉webpack预处理的实体增加comment.js,另外一个是告诉webpack输出的时候按照文件名字编译输出,而不是将所有js文件编译到bundle.js,[name]实际上是entry<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a>中的key,通过修改key可以归类目录,例如'comment/index':./src/index.js,'comment/index':'./src/comment.js'会将编译后的文件放到comment目录下,通过这些配置可以更好的组织代码结构</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" entry:{ 'index':'./src/index.js', 'comment':'./src/comment.js' }, output: { path: path.resolve(__dirname, 'build'), filename: '[name].js' }," title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs lua"><code> entry:{ <span class="hljs-string">'index'</span>:<span class="hljs-string">'./src/index.js'</span>, <span class="hljs-string">'comment'</span>:<span class="hljs-string">'./src/comment.js'</span> }, <span class="hljs-built_in">output</span>: { <span class="hljs-built_in">path</span>: <span class="hljs-built_in">path</span>.resolve(__dirname, <span class="hljs-string">'build'</span>), filename: <span class="hljs-string">'[name].js'</span> },</code></pre> <p>3、修改'build/index.html'引入文件修改为comment.js,重新运行webpack-dev-server,开始修改comment.js</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<script src=&quot;comment.js&quot;></script>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code style="word-break: break-word; white-space: initial;"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"comment.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre> <p>4、分拆Comment组件,梳理出如下结构,在<a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a>中所有的东西都是以组件的形式存在</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="- CommentBox - CommentList - Comment - CommentForm" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs sql"><code>- CommentBox - CommentList - <span class="hljs-keyword">Comment</span> - CommentForm</code></pre> <p>5、创建CommentBox组件,return()中的类html内容,在react中叫做<a href="http://www.js-code.com/tag/jsx" title="JSX" target="_blank">JSX</a>语法,其本身符合XML语法,react在编译后会转化为相应的js文件,官方介绍<a href="https://facebook.github.io/react/docs/jsx-in-depth.html" rel="nofollow noreferrer" target="_blank">https://facebook.github.io/re...</a><br />之后可以去浏览器中看下效果</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var CommentBox = <a href="http://www.js-code.com/tag/react" title="浏览关于“React”的文章" target="_blank" class="tag_link">React</a>.create<a href="http://www.js-code.com/tag/class" title="Class" target="_blank">Class</a>({<br /> render:function(){<br /> return (</p> <div className='commentBox'> Hello world! I am a comment box. </div> <p> )<br /> }<br /> });<br /> //渲染组件,注意修改index.html中<a href="http://www.js-code.com/tag/div" title="div" target="_blank">div</a>的id为content<br /> React<a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a>.render(<br /> <CommentBox ></CommentBox>,document.getElementById('content')<br /> );" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-keyword">var</span> CommentBox = React.create<a href="http://www.js-code.com/tag/class" title="浏览关于“Class”的文章" target="_blank" class="tag_link">Class</a>({ <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name"><a href="http://www.js-code.com/tag/div" title="浏览关于“div”的文章" target="_blank" class="tag_link">div</a></span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentBox'</span>&gt;</span> Hello world! I am a comment box. <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } }); <span class="hljs-comment">//渲染组件,注意修改index.html中div的id为content</span> React<a href="http://www.js-code.com/tag/dom" title="浏览关于“DOM”的文章" target="_blank" class="tag_link">DOM</a>.render( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">CommentBox</span> /&gt;</span>,document.getElementById('content') );</span></code></pre> <p>6、创建CommentList、CommentForm组件</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var CommentList = React.create<a href="http://www.js-code.com/tag/class" title="Class" target="_blank">Class</a>({<br /> render:function(){<br /> return (</p> <div className='commentList'> Hello, I am a comment list! </div> <p> )<br /> }<br /> });</p> <p>var CommentForm = React.createClass({<br /> render:function(){<br /> return (</p> <div className='commentForm'> hi, I am a comment form. </div> <p> )<br /> }<br /> });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-keyword">var</span> CommentList = React.createClass({ <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentList'</span>&gt;</span> Hello, I am a comment list! <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } }); <span class="hljs-keyword">var</span> CommentForm = React.createClass({ <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentForm'</span>&gt;</span> hi, I am a comment form. <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } });</code></pre> <p>7、修改CommentBox代码,引入CommentList、CommentForm组件。下面代码中混合了<a href="http://www.js-code.com/tag/html" title="HTML" target="_blank">HTML</a>和组件代码,<a href="http://www.js-code.com/tag/jsx" title="JSX" target="_blank">JSX</a>编译器会自动将<a href="http://www.js-code.com/tag/html" title="HTML" target="_blank">HTML</a>代码用React.createElement(tagName)去转换。浏览器看下效果。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var CommentBox = React.createClass({ render:function(){ return ( <div className='commentBox'> <h1>Comments</h1> <p> <CommentList ></CommentList><br /> <CommentForm ></CommentForm> </div> <p> )<br /> }<br /> });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-keyword">var</span> CommentBox = React.createClass({ <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentBox'</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Comments<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">CommentList</span> /&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">CommentForm</span> /&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } });</code></pre> <p>8、创建Comment组件,里面有{<a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.props.author}和{<a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.props.children}两个变量,称之为组件的属性。修改CommentList组件,可以看到我们传递了author属性。children是React预置属性,指向组件内嵌的内容。返回浏览器查看修改变化。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var Comment = React.createClass({ render:function(){ return ( <div className='comment'> <h2 className='commentAuthor'> {<a href="http://www.js-code.com/tag/this" title="浏览关于“this”的文章" target="_blank" class="tag_link">this</a>.props.author}<br /> </h2> <p> {this.props.children} </p></div> <p> )<br /> }<br /> })<br /> //修改CommentList组件,让其载入Comment组件<br /> var CommentList = React.createClass({<br /> render:function(){<br /> return (</p> <div className='commentList'> <Comment author='stone'>就是瞎比比</Comment><br /> <Comment author='mpanda'>我不听瞎比比</Comment> </div> <p> )<br /> }<br /> });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-keyword">var</span> Comment = React.createClass({ <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'comment'</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentAuthor'</span>&gt;</span> {this.props.author} <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span> {this.props.children} <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } }) <span class="hljs-comment">//修改CommentList组件,让其载入Comment组件</span> <span class="hljs-keyword">var</span> CommentList = React.createClass({ <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentList'</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">Comment</span> <span class="hljs-attr">author</span>=<span class="hljs-string">'stone'</span>&gt;</span>就是瞎比比<span class="hljs-tag">&lt;/<span class="hljs-name">Comment</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">Comment</span> <span class="hljs-attr">author</span>=<span class="hljs-string">'mpanda'</span>&gt;</span>我不听瞎比比<span class="hljs-tag">&lt;/<span class="hljs-name">Comment</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } });</code></pre> <p>9、添加Markdown支持</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="//安装依赖包 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}<br /> </h2> <p> {marked(this.props.children.toString())} </p></div> <p> )<br /> }<br /> })" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-comment">//安装依赖包</span> npm install marked --save <span class="hljs-comment">//引入marked包</span> <span class="hljs-keyword">var</span> marked = <span class="hljs-built_in">require</span>(<span class="hljs-string">'marked'</span>) <span class="hljs-comment">//修改Comment组件,利用marked组件解析评论内容,转为富文本格式。使用toString()是为了明确传送给marked的为字符串格式。浏览器看效果效果</span> <span class="hljs-keyword">var</span> Comment = React.createClass({ <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'comment'</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentAuthor'</span>&gt;</span> {this.props.author} <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span> {marked(this.props.children.toString())} <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> ) } })</code></pre> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="//显示效果 Comments stone <p>就是瞎比比</p> <p>mpanda</p> <p>我不听瞎比比</p> <p>hi, I am a comment form." title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code>//显示效果 Comments stone <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>就是瞎比比<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> mpanda <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>我不听瞎比比<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> hi, I am a comment form.</code></pre> <p>10、解析后的文本直接被显示在页面上,并没有被浏览器解析,这是react为了防止被<a href="https://en.wikipedia.org/wiki/Cross-site_scripting" rel="nofollow noreferrer" target="_blank">XSS攻击</a>而作的保护措施。React提供了一个并不友好的特殊<a href="http://www.js-code.com/tag/api" title="API" target="_blank">API</a>保证能够实现在浏览器显示原始<a href="http://www.js-code.com/tag/html" title="浏览关于“HTML”的文章" target="_blank" class="tag_link">HTML</a></p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="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}<br /> </h2> <p> <span dangerouslySetInnerHTML={this.rawMarkup()} ></span> </div> <p> )<br /> }<br /> })" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-keyword">var</span> Comment = React.createClass({ <span class="hljs-attr">rawMarkup</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">var</span> rawMarkup = marked(<span class="hljs-keyword">this</span>.props.children.toString(),{<span class="hljs-attr">sanitize</span>:<span class="hljs-literal">true</span>}) <span class="hljs-keyword">return</span> {<span class="hljs-attr">__html</span>:rawMarkup} }, <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'comment'</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentAuthor'</span>&gt;</span> {this.props.author} <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">dangerouslySetInnerHTML</span>=<span class="hljs-string">{this.rawMarkup()}</span> /&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> ) } })</span></code></pre> <p><a href="http://www.js-code.com/tag/jsx" title="浏览关于“JSX”的文章" target="_blank" class="tag_link">JSX</a>中dangerouslySetInnerHTML属性必须在接收到一个对象参数,且对象参数中明确使用__html作为key时,才会将其内容作为原始HTML插入页面中,而且不建议直接在&lt;<a href="http://www.js-code.com/tag/div" title="div" target="_blank">div</a> dangerouslySetInnerHTML={{__html:marked(this.props.children.toString(),{sanitize:true})}} /&gt;直接这样完成书写,目的就是明确提醒开发者,这里是有风险的,您是绝对的信任这段插入的内容。再次查看浏览器效果。It works!<br />11、评论数据显然应该来自服务器,不过在动态获取之前,我们先模拟一些数据</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var data = [ {&quot;id&quot;:1,&quot;author&quot;:&quot;stone&quot;,&quot;text&quot;:&quot;换一个位置瞎比比&quot;}, {&quot;id&quot;:2,&quot;author&quot;:&quot;mpanda&quot;,&quot;text&quot;:&quot;不喜欢你瞎比比&quot;}, ] //传递数据到CommentBox React<a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a>.render(<br /> <CommentBox data={data} ></span>,document.getElementById('content')<br /> );<br /> //直接传递数据到CommentList<br /> var CommentBox = React.createClass({<br /> render:function(){<br /> return (</p> <div className='commentBox'> <h1>Comments</h1> <p> <CommentList data={this.props.data} ></CommentList><br /> <CommentForm ></CommentForm> </div> <p> )<br /> }<br /> });<br /> //在CommentList重新完成组件的组装,刷新浏览器看效果<br /> var CommentList = React.createClass({<br /> render:function(){<br /> var commentNodes = this.props.data.map(function(comment){<br /> return (<br /> <Comment author={comment.author} key={comment.id}><br /> {comment.text}<br /> </Comment><br /> )<br /> });<br /> return (</p> <div className='commentList'> {commentNodes} </div> <p> )<br /> }<br /> });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code><span class="hljs-keyword">var</span> <span class="hljs-keyword">data</span> = [ {<span class="hljs-string">"id"</span>:<span class="hljs-number">1</span>,<span class="hljs-string">"author"</span>:<span class="hljs-string">"stone"</span>,<span class="hljs-string">"text"</span>:<span class="hljs-string">"换一个位置瞎比比"</span>}, {<span class="hljs-string">"id"</span>:<span class="hljs-number">2</span>,<span class="hljs-string">"author"</span>:<span class="hljs-string">"mpanda"</span>,<span class="hljs-string">"text"</span>:<span class="hljs-string">"不喜欢你瞎比比"</span>}, ] <span class="hljs-comment">//传递数据到CommentBox</span> ReactDOM.render( &lt;CommentBox <span class="hljs-keyword">data</span>={<span class="hljs-keyword">data</span>} /&gt;,document.getElementById(<span class="hljs-string">'content'</span>) ); <span class="hljs-comment">//直接传递数据到CommentList</span> <span class="hljs-keyword">var</span> CommentBox = React.createClass({ render:function(){ <span class="hljs-keyword">return</span> ( &lt;div className=<span class="hljs-string">'commentBox'</span>&gt; &lt;h1&gt;Comments&lt;/h1&gt; &lt;CommentList <span class="hljs-keyword">data</span>={<span class="hljs-keyword">this</span>.props.<span class="hljs-keyword">data</span>} /&gt; &lt;CommentForm /&gt; &lt;/div&gt; ) } }); <span class="hljs-comment">//在CommentList重新完成组件的组装,刷新浏览器看效果</span> <span class="hljs-keyword">var</span> CommentList = React.createClass({ render:function(){ <span class="hljs-keyword">var</span> commentNodes = <span class="hljs-keyword">this</span>.props.<span class="hljs-keyword">data</span>.map(function(comment){ <span class="hljs-keyword">return</span> ( &lt;Comment author={comment.author} key={comment.id}&gt; {comment.text} &lt;/Comment&gt; ) }); <span class="hljs-keyword">return</span> ( &lt;div className=<span class="hljs-string">'commentList'</span>&gt; {commentNodes} &lt;/div&gt; ) } });</code></pre> <p>12、从组件封装来说我们已经封装了一个很不错的组件,只需要传递相关json数据到CommentBox即可。不过所有的数据都是在组件创建的时候,利用不可变量参数props一次性传递给组件。state同样为组件的私有变量,可以通过this.set<a href="http://www.js-code.com/tag/state" title="State" target="_blank">State</a>()来设置变量的值,每次设置变量的值,组件都会重新渲染一遍自己。利用state修改我们的程序,让其动态渲染页面。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="//为了方便进行ajax请求,引入jquery,当然完全可以不引入 var $ = require(&quot;jquery&quot;) var CommentBox = React.createClass({ //getInitial<a href="http://www.js-code.com/tag/state" title="State" target="_blank">State</a>函数在组件的整个生命周期只会执行一次,我们在里面初始化数据<br /> getInitial<a href="http://www.js-code.com/tag/state" title="浏览关于“State”的文章" target="_blank" class="tag_link">State</a>:function(){<br /> return {data:[]}<br /> },<br /> //componentDidMount函数同样是有React自动调用,时间是在组件第一渲染完毕后。当然因为data在初始化的时候数据为空,实际上这时候渲染的组件没有内容。<br /> componentDidMount:function(){<br /> $.ajax({<br /> url:this.props.url,<br /> //因我本地server是php,且跨域,所以我们使用jsonp解决跨域问题,具体jsonp实现,请自行google<br /> dataType:&quot;jsonp&quot;,<br /> cache:false,<br /> jsonp:'callback',<br /> jsonpCallback:'getComment',<br /> success:function(data){<br /> //获取到数据后,通过<a href="http://www.js-code.com/tag/setstate" title="setState" target="_blank">setState</a>设置数据,组件会自动再次渲染<br /> this.<a href="http://www.js-code.com/tag/setstate" title="setState" target="_blank">setState</a>({&quot;data&quot;:data})<br /> }.bind(this),<br /> error:function(xhr,status,err){<br /> console.log(this.props.url,status,err.toString())<br /> }.bind(this)<br /> })<br /> },<br /> render:function(){<br /> return (</p> <div className='commentBox'> <h1>Comments</h1> <p> <CommentList data={this.state.data} ></CommentList><br /> <CommentForm ></CommentForm> </div> <p> )<br /> }<br /> });<br /> //将URL地址传递个组件<br /> ReactDOM.render(<br /> <CommentBox url=&quot;http://***.local.com/&quot; ></CommentBox>,document.getElementById('content')<br /> );" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs actionscript"><code><span class="hljs-comment">//为了方便进行ajax请求,引入jquery,当然完全可以不引入</span> <span class="hljs-keyword">var</span> $ = require(<span class="hljs-string">"jquery"</span>) <span class="hljs-keyword">var</span> CommentBox = React.createClass({ <span class="hljs-comment">//getInitialState函数在组件的整个生命周期只会执行一次,我们在里面初始化数据</span> getInitialState:<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span>{ <span class="hljs-keyword">return</span> {data:[]} }, <span class="hljs-comment">//componentDidMount函数同样是有React自动调用,时间是在组件第一渲染完毕后。当然因为data在初始化的时候数据为空,实际上这时候渲染的组件没有内容。</span> componentDidMount:<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span>{ $.ajax({ url:<span class="hljs-keyword">this</span>.props.url, <span class="hljs-comment">//因我本地server是php,且跨域,所以我们使用jsonp解决跨域问题,具体jsonp实现,请自行google</span> dataType:<span class="hljs-string">"jsonp"</span>, cache:<span class="hljs-literal">false</span>, jsonp:<span class="hljs-string">'callback'</span>, jsonpCallback:<span class="hljs-string">'getComment'</span>, success:<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(data)</span></span>{ <span class="hljs-comment">//获取到数据后,通过<a href="http://www.js-code.com/tag/setstate" title="浏览关于“setState”的文章" target="_blank" class="tag_link">setState</a>设置数据,组件会自动再次渲染</span> <span class="hljs-keyword">this</span>.setState({<span class="hljs-string">"data"</span>:data}) }.bind(<span class="hljs-keyword">this</span>), error:<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(xhr,status,err)</span></span>{ console.log(<span class="hljs-keyword">this</span>.props.url,status,err.toString()) }.bind(<span class="hljs-keyword">this</span>) }) }, render:<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span>{ <span class="hljs-keyword">return</span> ( &lt;div className=<span class="hljs-string">'commentBox'</span>&gt; &lt;h1&gt;Comments&lt;/h1&gt; &lt;CommentList data={<span class="hljs-keyword">this</span>.state.data} /&gt; &lt;CommentForm /&gt; &lt;/div&gt; ) } }); <span class="hljs-comment">//将URL地址传递个组件</span> ReactDOM.render( &lt;CommentBox url=<span class="hljs-string">"http://***.local.com/"</span> /&gt;,document.getElementById(<span class="hljs-string">'content'</span>) );</code></pre> <p>13、我们在浏览器看效果的时候因为数据请求都是在毫秒级别完成不方便看到重新渲染的效果,我们引入一个定时器。刷新浏览器,哈哈,2s后自动载入了评论数据。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var CommentBox = React.createClass({ getInitialState:function(){ return {data:[]} }, loadCommentsFromServer:function(){ $.ajax({ url:this.props.url, dataType:&quot;jsonp&quot;, cache:false, jsonp:'callback', jsonpCallback:'getComment', success:function(data){ this.setState({&quot;data&quot;: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> <p> <CommentList data={this.state.data} ></CommentList><br /> <CommentForm ></CommentForm> </div> <p> )<br /> }<br /> });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-keyword">var</span> CommentBox = React.createClass({ <span class="hljs-attr">getInitialState</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> {<span class="hljs-attr">data</span>:[]} }, <span class="hljs-attr">loadCommentsFromServer</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ $.ajax({ <span class="hljs-attr">url</span>:<span class="hljs-keyword">this</span>.props.url, <span class="hljs-attr">dataType</span>:<span class="hljs-string">"jsonp"</span>, <span class="hljs-attr">cache</span>:<span class="hljs-literal">false</span>, <span class="hljs-attr">jsonp</span>:<span class="hljs-string">'callback'</span>, <span class="hljs-attr">jsonpCallback</span>:<span class="hljs-string">'getComment'</span>, <span class="hljs-attr">success</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)</span>{ <span class="hljs-keyword">this</span>.setState({<span class="hljs-string">"data"</span>:data}) }.bind(<span class="hljs-keyword">this</span>), <span class="hljs-attr">error</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">xhr,status,err</span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.props.url,status,err.toString()) }.bind(<span class="hljs-keyword">this</span>) }) }, <span class="hljs-attr">componentDidMount</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ setInterval(<span class="hljs-keyword">this</span>.loadCommentsFromServer,<span class="hljs-number">2000</span>) }, <span class="hljs-attr">render</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'commentBox'</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Comments<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">CommentList</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{this.state.data}</span> /&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">CommentForm</span> /&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> ) } });</span></code></pre> <p>14、官方教程中评论提交分两种完成。第一种完成了提交完成后,需要刷新,再次从服务器获取评论数据,第二种提交评论后直接把提交的数据附加到评论后面,利用setState重新渲染页面。显然第二种体验更好,直接实现第二种。<br />先做分析,在CommentForm组件中,如果完成数据的提交,那么需要重新设置CommentList中的数据,但是CommentList的数据又是CommentBox传递过去的,那么提交数据的操作不如直接在CommentBox中完成,然后利用setState重新设置CommentList的数据,CommentList完成自动刷新。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="//之前获取评论接口利用的是jsonp,但是提交评论必须post方法,所以jsonp无法完成,但是有不能通过跨域操作。webpack支持proxy(代理)模式,可以把一部分接口直接转发到后端,修改webpack配置,请自行替换后端服务。 devServer:{ contentBase:'./build', proxy:{ &quot;/api/*&quot;:{ target:&quot;http://***.local.com:80&quot;, host:&quot;***.local.com&quot;, secure: false, }, bypass: function(req, res, proxyOptions) { if (req.headers.accept.indexOf('html') !== -1) { console.log('Skipping proxy for browser request.'); return '/index.html'; } }, } }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs javascript"><code><span class="hljs-comment">//之前获取评论接口利用的是jsonp,但是提交评论必须post方法,所以jsonp无法完成,但是有不能通过跨域操作。webpack支持proxy(代理)模式,可以把一部分接口直接转发到后端,修改webpack配置,请自行替换后端服务。</span> devServer:{ <span class="hljs-attr">contentBase</span>:<span class="hljs-string">'./build'</span>, <span class="hljs-attr">proxy</span>:{ <span class="hljs-string">"/api/*"</span>:{ <span class="hljs-attr">target</span>:<span class="hljs-string">"http://***.local.com:80"</span>, <span class="hljs-attr">host</span>:<span class="hljs-string">"***.local.com"</span>, <span class="hljs-attr">secure</span>: <span class="hljs-literal">false</span>, }, <span class="hljs-attr">bypass</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">req, res, proxyOptions</span>) </span>{ <span class="hljs-keyword">if</span> (req.headers.accept.indexOf(<span class="hljs-string">'html'</span>) !== <span class="hljs-number">-1</span>) { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Skipping proxy for browser request.'</span>); <span class="hljs-keyword">return</span> <span class="hljs-string">'/index.html'</span>; } }, } }</code></pre> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="//注意传递的url,会自动转发到http://***.local.com:80/api/comment ReactDOM.render( <CommentBox url=&quot;http://localhost:8080/api/comment&quot; ></span>,document.getElementById('content')<br /> );" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs typescript"><code><span class="hljs-comment">//注意传递的url,会自动转发到http://***.local.com:80/api/comment</span> ReactDOM.render( &lt;CommentBox url=<span class="hljs-string">"http://localhost:8080/api/comment"</span> /&gt;,<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'content'</span>) );</code></pre> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var CommentBox = React.createClass({ //增加评论提交方法,后台服务 handleSubmitComment:function(data){ $.ajax({ //请注意,后台接口我把评论和获取评论放到了一起,只是提交方式不一样,一个是get,一个是post url:this.props.url, type:&quot;POST&quot;, data:data, dataType:&quot;json&quot;, 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> <p> <CommentList data={this.state.data} ></CommentList><br /> //将评论提交接口传递个CommentForm组件<br /> <CommentForm onSubmitComment={this.handleSubmitComment} ></CommentForm> </div> <p> )<br /> }<br /> });</p> <p>var CommentForm = React.createClass({<br /> getInitialState:function() {<br /> return {author:&quot;&quot;,text:&quot;&quot;}<br /> },<br /> //完成数据的绑定,通过setState也能保证跟此数据相关的UI完成重新的渲染<br /> handleAuthorChange:function(event){<br /> this.setState({author:event.target.value})<br /> },<br /> handleTextChange:function(event){<br /> this.setState({text:event.target.value})<br /> },<br /> handleSubmit:function(event){<br /> //组织表单默认的submit提交<br /> event.preventDefault();<br /> var author = this.state.author.trim()<br /> var text = this.state.text.trim()<br /> if(!text||!author) {<br /> return;<br /> }<br /> //调用CommentBox上的评论提交方法<br /> this.props.onSubmitComment({author:author,text:text});<br /> this.setState({author:&quot;&quot;,text:&quot;&quot;})<br /> },</p> <p> render:function(){<br /> return (</p> <form className='commentForm' onSubmit={this.handleSubmit}> <input type='text' onChange={this.handleAuthorChange} placeholder='怎么称呼您呢?爷' value={this.state.author} /><br /> <input type='text' onChange={this.handleTextChange} placeholder='爷有什么赐教?' value={this.state.text} /><br /> <input type='submit' value='提交' /><br /> </form> <p> )<br /> }<br /> });" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code><span class="hljs-keyword">var</span> CommentBox = React.createClass({ <span class="hljs-comment">//增加评论提交方法,后台服务 </span> handleSubmitComment:function(<span class="hljs-keyword">data</span>){ $.ajax({ <span class="hljs-comment">//请注意,后台接口我把评论和获取评论放到了一起,只是提交方式不一样,一个是get,一个是post</span> url:<span class="hljs-keyword">this</span>.props.url, type:<span class="hljs-string">"POST"</span>, <span class="hljs-keyword">data</span>:<span class="hljs-keyword">data</span>, dataType:<span class="hljs-string">"json"</span>, cache:<span class="hljs-literal">false</span>, success:function(<span class="hljs-keyword">data</span>){ <span class="hljs-comment">//测试接口直接返回了我提交的内容,所以可以直接附加数据,让CommentList自动刷新</span> <span class="hljs-keyword">this</span>.setState({<span class="hljs-keyword">data</span>:<span class="hljs-keyword">this</span>.state.<span class="hljs-keyword">data</span>.concat(<span class="hljs-keyword">data</span>)}); }.bind(<span class="hljs-keyword">this</span>), error:function(xhr,status,err){ console.log(<span class="hljs-keyword">this</span>.props.url,status,err.toString()) }.bind(<span class="hljs-keyword">this</span>) }) }, render:function(){ <span class="hljs-keyword">return</span> ( &lt;div className=<span class="hljs-string">'commentBox'</span>&gt; &lt;h1&gt;Comments&lt;/h1&gt; &lt;CommentList <span class="hljs-keyword">data</span>={<span class="hljs-keyword">this</span>.state.<span class="hljs-keyword">data</span>} /&gt; <span class="hljs-comment">//将评论提交接口传递个CommentForm组件</span> &lt;CommentForm onSubmitComment={<span class="hljs-keyword">this</span>.handleSubmitComment} /&gt; &lt;/div&gt; ) } }); <span class="hljs-keyword">var</span> CommentForm = React.createClass({ getInitialState:function() { <span class="hljs-keyword">return</span> {author:<span class="hljs-string">""</span>,text:<span class="hljs-string">""</span>} }, <span class="hljs-comment">//完成数据的绑定,通过setState也能保证跟此数据相关的UI完成重新的渲染</span> handleAuthorChange:function(event){ <span class="hljs-keyword">this</span>.setState({author:event.target.value}) }, handleTextChange:function(event){ <span class="hljs-keyword">this</span>.setState({text:event.target.value}) }, handleSubmit:function(event){ <span class="hljs-comment">//组织表单默认的submit提交</span> event.preventDefault(); <span class="hljs-keyword">var</span> author = <span class="hljs-keyword">this</span>.state.author.trim() <span class="hljs-keyword">var</span> text = <span class="hljs-keyword">this</span>.state.text.trim() <span class="hljs-keyword">if</span>(!text||!author) { <span class="hljs-keyword">return</span>; } <span class="hljs-comment">//调用CommentBox上的评论提交方法</span> <span class="hljs-keyword">this</span>.props.onSubmitComment({author:author,text:text}); <span class="hljs-keyword">this</span>.setState({author:<span class="hljs-string">""</span>,text:<span class="hljs-string">""</span>}) }, render:function(){ <span class="hljs-keyword">return</span> ( &lt;form className=<span class="hljs-string">'commentForm'</span> onSubmit={<span class="hljs-keyword">this</span>.handleSubmit}&gt; &lt;input type=<span class="hljs-string">'text'</span> onChange={<span class="hljs-keyword">this</span>.handleAuthorChange} placeholder=<span class="hljs-string">'怎么称呼您呢?爷'</span> value={<span class="hljs-keyword">this</span>.state.author} /&gt; &lt;input type=<span class="hljs-string">'text'</span> onChange={<span class="hljs-keyword">this</span>.handleTextChange} placeholder=<span class="hljs-string">'爷有什么赐教?'</span> value={<span class="hljs-keyword">this</span>.state.text} /&gt; &lt;input type=<span class="hljs-string">'submit'</span> value=<span class="hljs-string">'提交'</span> /&gt; &lt;/form&gt; ) } });</code></pre> <p>到此整个示例联系完成!之后要完成用<a href="http://www.js-code.com/tag/es6" title="es6" target="_blank">es6</a>语法重构该项目。</p> <p></code></p>

本文固定链接: http://www.js-code.com/react/react_43689.html