React组件综合案例(★★★)
需求分析
渲染评论列表(列表渲染)
没有评论数据时渲染:暂无评论(条件渲染)
获取评论信息,包括评论人和评论内容(受控组件)
发表评论,更新评论列表(setState())
搭建评论列表的模板
结构
importReactfrom'react'importReactDOMfrom'react-dom'/* 评论列表案例comments: [{ id: 1, name: 'jack', content: '沙发!!!' },{ id: 2, name: 'rose', content: '板凳~' },{ id: 3, name: 'tom', content: '楼主好人' }]*/import'./index.css'classAppextendsReact.Component { render() { return ( <divclassName="app"><div><inputclassName="user"type="text"placeholder="请输入评论人"/><br/><textareaclassName="content"cols="30"rows="10"placeholder="请输入评论内容"/><br/><button>发表评论</button></div><divclassName="no-comment">暂无评论,快去评论吧~</div><ul><li><h3>评论人:jack</h3><p>评论内容:沙发!!!</p></li></ul></div> ) } } // 渲染组件ReactDOM.render(<App/>, document.getElementById('root'))
样式
.app { width: 300px; padding: 10px; border: 1pxsolid#999; } .user { width: 100%; box-sizing: border-box; margin-bottom: 10px; } .content { width: 100%; box-sizing: border-box; margin-bottom: 10px; } .no-comment { text-align: center; margin-top: 30px; }
渲染评论列表
在state中初始化评论列表数据
state= { comments: [ { id: 1, name: 'jack', content: '沙发!!!' }, { id: 2, name: 'rose', content: '板凳~' }, { id: 3, name: 'tom', content: '楼主好人' } ] }
使用数组的map方法遍历state中的列表数据
给每一个被遍历的li元素添加key属性
在render方法里的ul节点下嵌入表达式
{ this.state.comments.map(item=> { return ( <likey={item.id}><h3>{item.name}</h3><p>{item.content}</p></li> ) }) }
渲染暂无评论
判断列表数据的长度是否为0
如果为0,则渲染暂无评论
如果不为0,那么渲染列表数据
在jsx中大量写逻辑会导致很臃肿,所以我们可以把条件渲染的逻辑抽取成一个函数
/*** 条件渲染,这里抽取出来了,这样在结构中不会很混乱*/renderList(){ if (this.state.comments.length===0) { return (<divclassName="no-comment">暂无评论,快去评论吧~</div>) } else { return ( <ul> { this.state.comments.map(item=> { return ( <likey={item.id}><h3>{item.name}</h3><p>{item.content}</p></li> ) }) } </ul> ) } }
在render的return方法里面调用这个函数即可
render() { return ( <div> ... {/* 通过条件渲染来判断是否显示暂无评论 */} {this.renderList()} </div> ) }
获取评论信息
通过受控组件来获取内容
初始化用户名和用户内容的state
userName: '', userContent: ''
在结构中,把表单元素的value与state进行绑定,还需要绑定name属性和onChange属性
<inputclassName="user"type="text"placeholder="请输入评论人"value={this.state.userName} name="userName"onChange={this.handleForm}/><br/><textareaclassName="content"cols="30"rows="10"placeholder="请输入评论内容"value={this.state.userContent} name="userContent"onChange={this.handleForm} />
在handleFrom函数中利用setState来让数据保持一致
handleForm= (e) => { this.setState({ [e.target.name] : e.target.value }) }
发表评论
给按钮绑定事件
在事件处理程序中,通过state获取评论信息
将评论信息添加到state中,利用setState来更新页面
添加评论前需要判断用户是否输入内容
添加评论后,需要情况文本框用户输入的值
handleClick= (e) => { // 拿到用户输入的内容let {userName,userContent} =this.stateif(userName.trim()===''||userContent.trim() ===''){ alert('请输入内容') return } // 利用数组拓展运算符来进行数据的拼接,把用户输入的存放在数组的第一个位置letnewComments= [{ id: this.state.comments.length+1, name: userName, content: userContent },...this.state.comments] this.setState({ comments: newComments, userName:'', userContent: '' }) }