受控组件
1、什么是受控组件
- 受控组件通常指的是表单,因为HTML中的表单是可输入的,也就是有自己的可变状态
- React中可变状态通常保存在state 中,并且只能通过setState()方法来修改
- React 将 state与表单的 value值绑定到一起,给表单元素绑定change事件,将表单元素的值设置为
state的值,接收表单值变化
2、核心步骤
第一步:在state中设置数据
state = {
txt:''
}
第二步:表单域中将 state中的数据与value绑定
<input
type="text"
value={this.state.txt}
</input>
此时,value与txt 绑定,所以文本框中默认写入
第三步:给表单绑定onChange事件
<input
type="text"
value={this.state.txt}
onChange={this.handleChange}>
</input>
第四步:事件函数中调用 setState 将数据进行保存
handleChange = e=>{
this.setState({
txt:e.target.value
})
}
参数:e
是事件对象e.target.value
保存了input中的value值
3、不同域数据的获取方式
- 每个域都要将 value 和 state 中对应的属性绑定
- 每个域都要绑定 onChange 事件
举例: 点击登录按钮,将文本框中的值输出到终端
给input、select、textarea表单域分别绑定onChange事件
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = {
txt: '1234',
city: '北京',
desc: '好好学习,天天向上'
}
handleChange = e => {
this.setState({
txt: e.target.value
})
}
handleCity = e => {
this.setState({
city: e.target.value
})
}
handleDesc = e => {
this.setState({
desc: e.target.value
})
}
submit = () => {
console.log(this.state)
}
render () {
return (
<div>
账号: <input type="text" value={this.txt} onChange={this.handleChange} /><br />
城市: <select value={this.city} onChange={this.handleCity}>
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="sz">深圳</option>
</select><br />
描述: <textarea value={this.desc} onChange={this.handleDesc}></textarea><br />
<button onClick={this.submit}>登录</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
当我们输入数据之后,根据每个域的属性绑定,点击登录按钮,终端会显示出我们输入的数据
4、合并处理
核心:e.target
- e.target.value : 保存了标签中的value值
- e.target.name:保存了标签中的name值
每个域中name属性绑定 state 中对应的属性, onChange指定一个函数统一处理
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = {
account: '',
city: '',
desc: ''
}
handleForm = e => {
const {name, value} = e.target
this.setState({
[name]: value
})
}
submit = () => {
console.log(this.state)
}
render () {
return (
<div>
账号: <input name="account" type="text" value={this.account} onChange={this.handleForm} /><br />
城市: <select name="city" value={this.city} onChange={this.handleForm}>
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="sz">深圳</option>
</select><br />
描述: <textarea name="desc" value={this.desc} onChange={this.handleForm}></textarea><br />
<button onClick={this.submit}>登录</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
案例:评论列表
- 渲染评论列表,利用
列表渲染
方法 - 没有列表数据时渲染:暂无评论,利用
条件渲染
方法 - 获取评论信息,包括评论人和评论内容,利用
受控组件
- 发表评论,更新评论列表,使用
setState()
方法
1、渲染评论列表
- 在state中初始化评论列表数据
state={
//初始化状态
comment:[
{id:1,name:'小王',content:'你好机智'},
{id:2,name:'小赵',content:'你好笨'},
{id:3,name:'小刘',content:'你好完美'}
]
}
- 使用数组的map方法遍历state中的列表数据
- 给每个被遍历的li元素添加key属性,可以避免评论信息一样
<ul>
{
this.state.comment.map(item=>(
<li key = {item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))}
</ul>
2、渲染暂无评论
判断列表长度是否为0,如果长度为0,便渲染暂无评论
//渲染评论列表
renderList(){
return this.state.comment.length === 0?
(<div className='no-content'> 暂无评论,快去评论吧 </div>)
:( <ul>
{this.state.comment.map(item=>(
<li key = {item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))}
</ul>)
}
效果:
3、获取表单信息
准备状态分别控制两个表单元素,并通过创建一个函数处理表单元素值,使onChange指定这个函数统一处理,并且name属性需绑定 state 中对应的属性
//评论人
userName:'',
//评论信息
userContent:''
handleForm = (e) =>{
const {name,value} = e.target
this.setState({
[name]:value
})
}
4、发表评论
给按钮绑定单击事件,在事件处理程序中,通过state获取评论信息,并将评论信息添加到state中,并调用setState()方法来更新state
//发表评论
addComment = ()=>{
const {comment,userName,userContent} = this.state
console.log(userName,userContent);
const newComment = [{
id:Math.random(),
name:userName,
content:userContent
},...comment]
console.log(newComment)
this.setState({
comment:newComment
})
}
效果:发出评论之后,可以将评论置顶在第一条
完整代码:
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state={
//初始化状态
comment:[
{id:1,name:'小王',content:'你好机智'},
{id:2,name:'小赵',content:'你好笨'},
{id:3,name:'小刘',content:'你好完美'}
],
//评论人
userName:'',
//评论信息
userContent:''
}
//渲染评论列表
renderList(){
return this.state.comment.length === 0?
(<div className='no-content'> 暂无评论,快去评论吧 </div>)
:( <ul>
{this.state.comment.map(item=>(
<li key = {item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))}
</ul>)
}
//处理表单元素值
handleForm = (e) =>{
const {name,value} = e.target
this.setState({
[name]:value
})
}
//发表评论
addComment = ()=>{
const {comment,userName,userContent} = this.state
console.log(userName,userContent);
//非空校验
if(userName.trim()===''||userContent.trim()===''){
alert('请输入评论人和评论内容')
return
}
const newComment = [{
id:Math.random(),
name:userName,
content:userContent
},...comment]
console.log(newComment)
this.setState({
comment:newComment,
//在点击完评论之后清空文本框
userName:'',
userContent:''
})
}
render () {
const {userName,userContent} = this.state
return (
<div className='app'>
<div>
<input className='user' type='text' placeholder="请输入评论人" value={userName} name='userName' onChange={this.handleForm}/>
<br/>
<textarea
className='content'
cols='30'
rows='10'
placeholder="请输入评论内容"
value={userContent}
onChange={this.handleForm}
name = "userContent"
/>
<br/>
<button onClick={this.addComment}>发表评论</button>
</div>
{this.renderList()}
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))