目录
- 1. 受控组件
- 1.1 介绍
- 1.2 受控组件简写
- 1.3 在表单中使用受控组件
- 1.4 综合案例
- 2. 非受控组件介绍
- 非受控组件的应用
1. 受控组件
1.1 介绍
概述:
将 state 与表单项中的 value 值绑定在一起,有 state 的值来控制表单元素的值,称为受控组件。
绑定步骤:
- 在state中添加一个状态,作为表单元素的value值
- 给表单元素绑定 change 事件,将表单元素的值设置为 state 的值
语法:
# value={this.state.xx} 事件onChange=“方法,修改state中的数据”
<input type="text" value={this.state.username} onChange={this.inputChange.bind(this)} />
注:多表单元素需优化事件方法
this.setState({
[e.target.name]: e.target.value
})
使用:
import React, { Component } from 'react';
class App extends Component {
state = {
username: '',
password: ''
}
setValue = name => evt => {
this.setState({
// 变量的值当前对象的key,写法
[name]: evt.target.value.trim()
})
}
login = () => {
console.log(this.state);
}
render() {
let { username, password } = this.state
return (
<div>
<div>
{/*
表单项中的value值,通过state中的属性值来赋值的,叫受控组件
受控组件: value={this.state.xx} 事件onChange=“方法,修改state中的数据”
*/}
<input type="text" value={username} onChange={this.setValue('username')} />
</div>
<div>
<input type="text" value={password} onChange={this.setValue('password')} />
</div>
<div>
<button onClick={this.login}>登录一下</button>
</div>
</div>
);
}
}
export default App;
1.2 受控组件简写
同样是实现上面案例中的场景,我们还可以有简写方式。
loginForm.js:
export default _this => ({
username: {
value: '',
onChange: e => _this.setState(state => ({ username: { ...state.username, value: e.target.value } }))
},
password: {
value: '',
onChange: e => _this.setState(state => ({ password: { ...state.password, value: e.target.value } }))
}
})
App.jsx:
import React, { Component } from 'react';
import loginForm from './form/loginForm';
class App extends Component {
state = {
...loginForm(this),
num: 100
}
login = () => {
console.log(this.state);
}
render() {
let { username, password } = this.state
return (
<div>
<div>
{/* 相当于 value={username} onChange={this.setValue('username')} */}
<input type="text" {...username} />
</div>
<div>
<input type="text" {...password} />
</div>
<div>
<button onClick={this.login}>登录一下</button>
</div>
</div>
);
}
}
export default App;
1.3 在表单中使用受控组件
import React, { Component } from 'react';
class App extends Component {
state = {
username: '',
sex: '女',
isshow: true,
lessons: ['html', 'js']
}
setLessonsFn = e => {
if (e.target.checked) {
this.setState(state => ({
lessons: [...state.lessons, e.target.value]
}))
} else {
this.setState(state => ({
lessons: state.lessons.filter(item => item != e.target.value)
}))
}
}
login = () => {
console.log(this.state);
}
render() {
let { username, sex, isshow,lessons } = this.state
return (
<div>
<div>
<input type="text" value={username} onChange={e => this.setState({ username: e.target.value })} />
</div>
<div>
{/* 单选 */}
<input type="radio" name='sex' checked={sex === '男'} value='男' onChange={e => this.setState({ sex: e.target.value })} />男
<input type="radio" name='sex' checked={sex === '女'} value='女' onChange={e => this.setState({ sex: e.target.value })} />女
</div>
<div>
{/* 单个复选框 */}
<input type="checkbox" checked={isshow} onChange={e => this.setState({ isshow: e.target.checked })} /> 显示与隐藏
</div>
<div>
{/* 多个复选框 */}
<div>
<input type="checkbox" value='html' checked={lessons.includes('html')} onChange={this.setLessonsFn} />html
<input type="checkbox" value='css' checked={lessons.includes('css')} onChange={this.setLessonsFn} />css
<input type="checkbox" value='js' checked={lessons.includes('js')} onChange={this.setLessonsFn} />js
</div>
</div>
<div>
<button onClick={this.login}>登录一下</button>
</div>
</div>
);
}
}
export default App;
1.4 综合案例
全选与反选,显示与隐藏的应用
描述:
本案例中我们将要实现,对用户名和密码进行正则验证(账号只能是邮箱或手机号,别的不行;密码必须是3位以上且有数字和字母 ),验证成功后点击登录下方显示用户列表。用户列表有删除功能,有全选和取消全选功能。选中所有的子项,全选就自动勾选,有一个子项没选中,全选就取消勾选 。
实现:
App.jsx:
import React, { Component } from 'react';
import UserTable from './components/UserTable';
class App extends Component {
state = {
username: '',
password: '',
show: false,
}
// 通过onChange事件来修改state中对应属性变化
setUsername = evt => {
// console.log(evt.target.value.trim());
this.setState({
username: evt.target.value.trim()
})
}
setPassword = evt => {
this.setState({
password: evt.target.value.trim()
})
}
setValue = name => evt => {
this.setState({
// 变量的值当前对象的key,写法
[name]: evt.target.value.trim()
})
}
submit = () => {
if (this.regExpValue(this.state.username, "username") && this.regExpValue(this.state.password, "password")) {
alert("登录成功!")
this.login()
} else {
alert("正则验证失败,请重新输入!")
}
}
regExpValue = (value, key) => {
if (key === "username") {
return /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value) || /^1[3-9][0-9]{9}$/.test(value);
} else {
return /(?=.*?[A-Za-z])(?=.*?[0-9]).{3,}/.test(value);
}
}
login = () => {
// this.setState.show=true
this.setState({ show: true });
console.log(this.state.show);
}
render() {
let { username, password, show } = this.state
return (
<div>
<div>
{/*
表单项中的value值,通过state中的属性值来赋值的,叫受控组件
受控组件: value={this.state.xx} 事件onChange=“方法,修改state中的数据”
*/}
<input type="text" value={username} onChange={this.setValue('username')} />
</div>
<div>
<input type="text" value={password} onChange={this.setValue('password')} />
</div>
<div>
<button onClick={this.submit}>登录一下</button>
</div>
{
this.state.show
?
<UserTable />
:
<div>不显示</div>
}
</div>
);
}
}
export default App;
UserTable.jsx:
import { getElementError } from '@testing-library/react';
import React, { Component } from 'react';
class UserTable extends Component {
state = {
users: [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' },
{ id: 4, name: '赵六' },
],
isshow: true,
uids: [],
tip: '全选',
}
all = e => {
e.target.checked
?
this.setState(state => ({
uids: state.users.map(({ id }) => id),
tip: '取消全选'
}))
:
this.setState({ uids: [], tip: '全选' })
console.log(this.state.uids);
}
select = tid => e => {
let all = document.querySelector(".all");
if (e.target.checked) {
setTimeout(() => {
this.setState(state => ({
uids: [...state.uids, tid]
}))
if (this.state.uids.length === 4) all.checked = true
}, 0);
} else {
setTimeout(() => {
this.setState(state => ({
uids: state.uids.filter(item => item != tid)
}))
all.checked = false
console.log(this.state.uids);
}, 0);
}
}
del = tid => () => {
this.setState(state => ({
users: state.users.filter(({ id }) => id !== tid)
}))
}
render() {
let { users, uids, tip } = this.state
return (
<div>
<input type="checkbox" onChange={this.all} className="all" />{tip}
<hr />
<ul>
{
users.map(({ id, name }) => (
<li key={id}>
<span>
<input type="checkbox" checked={uids.includes(id)} onChange={this.select(id)} />
</span>
<span>{name} -- {id}</span>
<span onClick={this.del(id)}>删除</span>
</li>
))
}
</ul>
</div>
);
}
}
export default UserTable;
2. 非受控组件介绍
概述:
表单项中的 value 或 checked 值,它不受 state 中的属性控制,但是可以而是借助 ref,通过 dom 对象来获取当前表单项中的 value 或 checked 值,这就是非受控组件。
非受控组件的应用的次数没有受控组件多,在工作中,多数使用为受控组件。
注意:react 中如何来获取普通的 html 元素的 dom 对象:ref 对象来获取。
使用步骤:
- 调用 React.createRef() 方法创建ref对象
- 将创建好的 ref 对象添加到文本框中
- 通过ref对象获取到文本框的值
语法:
class App extends React.Component {
constructor(props){
super(props)
//创建 ref
this.username = React.createRef()
}
// 获取文本框的值
fn =() => {
console.log(this.username.current.value)
}
render(){
return (
<div>
<input type ="text" ref={this.username} />
<button onClick ={this.fn}>获取值</button>
</div>
)
}
}
示例:
// createRef 通过此方法得到一个ref实例对象
// ref 如果绑定在普通的html元素中则返回dom对象
// ref 如果绑定在"类组件"中,则返回当前自定义类组件实例对象,可以用它来完成组件通信
import React, { Component, createRef } from 'react'
class App extends Component {
// 创建得到一个ref实例对象
usernameRef = createRef()
getUsernameInput = () => {
// 通过ref绑定好的对象,来完成对应表单项数据的获取
console.log(this.usernameRef.current.value)
}
render() {
return (
<div>
<input type="text" ref={this.usernameRef} />
<button onClick={this.getUsernameInput}>获取表单项中的数据</button>
</div>
)
}
}
export default App
注意:
- createRef:通过此方法可以得到一个 ref 实例对象
- ref 如果绑定在普通的html元素中则返回dom对象
- ref 如果绑定在"类组件"中,则返回当前自定义类组件实例对象,可以用它来完成组件通信
非受控组件的应用
import React, { Component, createRef } from 'react'
class App extends Component {
// 创建得到一个ref实例对象
usernameRef = createRef()
isShowRef = createRef()
// 等同于:lessonsRefs = [createRef(), createRef(), createRef()]
lessonsRefs = Array(3)
.fill('')
.map(_ => createRef())
getUsernameInput = evt => {
// 通过dom向上查找,不推荐,层级不确定,有时候会找不到
// console.dir(evt.target.previousSibling.value)
// 通过ref绑定好的对象,来完成对应表单项数据的获取
console.log(this.usernameRef.current.value)
if (this.isShowRef.current.checked) {
console.log(this.isShowRef.current.value)
}
console.log(
this.lessonsRefs
.map(item => {
if (item.current.checked) {
return item.current.value
} else {
return null
}
})
.filter(item => item != null)
)
}
render() {
return (
<div>
<input type="text" ref={this.usernameRef} />
<br />
<input type="checkbox" value="aaa" ref={this.isShowRef} />aaa
<br />
<input type="checkbox" value="html" ref={this.lessonsRefs[0]} />html
<input type="checkbox" value="css" ref={this.lessonsRefs[1]} />css
<input type="checkbox" value="js" ref={this.lessonsRefs[2]} />js
<button onClick={this.getUsernameInput}>获取表单项中的数据</button>
</div>
)
}
}
export default App
注意:
获取表单数据可以有两种方案
通过 dom 向上查找,这种方案不推荐,因为 dom 层级不确定,有时候会找不到数据
console.dir(evt.target.previousSibling.value)
通过ref绑定好的对象,来完成对应表单项数据的获取\
console.log(this.usernameRef.current.value)