文章目录
事件处理
- 通过onXxx属性指定事件处理函数(注意大小写)
- React使用的是自定义(合成)事件, 而不是使用的原生DOM事件。
优点:onClick是比onclick(原生事件)兼容性更好 - React中的事件是通过
事件委托
方式处理的(委托给组件最外层的元素
)
优点:更高效 - 在jsx语法中的事件属性接受的是函数,所以函数名后面无需写
()
;如果必须要传递参数,需要该函数的返回值也是一个函数。
eg:
import React, {
Component } from 'react'
import PropyTypes from 'prop-types'
import './index.css'
export default class index extends Component {
// 对Props进行类型的限制
static propsTypes = {
updateTodo: PropyTypes.func.isRequired,
id: PropyTypes.string.isRequired,
name: PropyTypes.string.isRequired,
done: PropyTypes.bool.isRequired
}
state = {
mouse:false}
handleMouse = (flag)=>{
// 在标签中函数使用了括号
return () => {
this.setState({
mouse:flag})
}
}
handleChange = (id) => {
return (event) => {
// 注意是checked不是value
const checked = event.target.checked;
this.props.updateTodo(id, checked)
}
}
handleDelete = (id)=>{
if(window.confirm("确定删除吗?")){
this.props.deleteTodo(id)
}
}
render() {
const {
id, name, done} = this.props
const {
mouse} = this.state;
return (
<li style={
{
backgroundColor: mouse? '#ddd':'white'}} onMouseEnter = {
this.handleMouse(true)} onMouseLeave = {
this.handleMouse(false)}>
<label>
{
/* 使用checked,必须要结合onChange事件才能进行修改
而defaultChecked,初次页面展示时是否勾选,当数据再发生改变的时候就不好用了*/}
<input type="checkbox" checked = {
done} onChange = {
this.handleChange(id)}/>
<span>{
name}</span>
</label>
<button onClick={
() => {
this.handleDelete(id)}} className="btn btn-danger" style={
{
display:mouse?"block":"none"}}>删除</button>
</li>
)
}
}
- 可以使用ref来存储当前节点,再结合事件的回调函数进行节点数据的处理。
- 也 可以通过
event.target
得到发生事件的DOM元素对象
当发生事件的元素正好是要操作的元素的时候我们尽量使用evet.target获取数据,不要过度地使ref
eg:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>字符串ref</title>
</head>
<body>
<!-- 容器 -->
<div id="test"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
// <!-- 1.创建类式组件 -->
class Demo extends React.Component{
// React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专川用”的(即一个createRef只能存储一个dom元素)
myRef = React.createRef()
showDataClick = ()=>{
alert(this.myRef.current.value)
}
showDataBlur = (event)=>{
// event发生事件的事件源
alert(event.target.value)
}
render(){
return (
<div>
{
/*ref方式*/}
<input ref={
this.myRef} type="text" id="input1" placeholder="点击按钮提示数据"/>
<button onClick={
this.showDataClick}>点我提示左侧数据</button>
{
/*event.Target方式*/}
<input onBlur={
this.showDataBlur} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
// <!--2.渲染虚拟DOM到页面 -->
ReactDOM.render(<Demo/>,document.getElementById('test'))
</script>
</body>
</html>
受控组件和非受控组件
- 非受控组件:表单中所有
输入类
的DOM现用现取
的就是非受控组件
现用现取
即需要用到该数据的时候再获取 - 受控组件:将数据先存放在state中,再显示到页面上。——有点类似于vue的双向数据绑定,只不过在react中需要自己手动实现。
需求:
有用户名和密码,当点击登陆的时候会弹窗提示用户名和密码。
受控组件实现:——数据存储在state
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>受控组件</title>
</head>
<body>
<!-- 容器 -->
<div id="test"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
// <!-- 1.创建类式组件 -->
class Login extends React.Component{
// 初始化状态
state={
username:'',
password:''
}
handlesubmit = (event)=>{
event.preventDefault()//阻止默认事件,表单的提交
const {
username,password} = this.state
alert(`用户名:${
username},密码:${
password}`)
}
// 保存用户名到username
saveUsername = (event)=>{
this.setState({
username:event.target.value})
}
// 保存
savePassword = (event)=>{
this.setState({
password:event.target.value})
}
render(){
return(
<form action="http://www.baidu.com" onSubmit={
this.handlesubmit} >
{
/*onchange也是一个原生的事件,当内容发生改变就会调用该函数*/}
用户名:<input onChange={
this.saveUsername} type="text" name="username"/><br/>
密码:<input onChange={
this.savePassword} type="password" name="password"/><br/>
<button>登录</button>
</form>
)
}
}
// <!--2.渲染虚拟DOM到页面 -->
ReactDOM.render(<Login/>,document.getElementById('test'))
</script>
<!-- 受控组件:数据先存放在state中,再显示到页面上 -->
</body>
</html>
非受控组件实现:—— 数据存储在组件实例上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>非受控组件</title>
</head>
<body>
<!-- 容器 -->
<div id="test"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
// <!-- 1.创建类式组件 -->
class Login extends React.Component{
handlesubmit = (event)=>{
event.preventDefault()//阻止默认事件,表单的提交
const {
username,password} = this
alert(`用户名:${
username.value},密码:${
password.value}`)
}
render(){
return(
// form表单默认是get请求,query参数
// form会默认提交并刷新页面,即使没有配路径
<form action="http://www.baidu.com" onSubmit={
this.handlesubmit} >
用户名:<input ref={
c=>this.username=c} type="text" name="username"/><br/>
密码:<input ref={
c=>this.password=c} type="password" name="password"/><br/>
<button>登录</button>
</form>
)
}
}
// <!--2.渲染虚拟DOM到页面 -->
ReactDOM.render(<Login/>,document.getElementById('test'))
</script>
<!-- 非受控组件:表单中所有输入类的DOM 现用现取的就是非受控组件 -->
</body>
</html>
高阶函数和函数柯里化
高阶函数
上述代码有点冗余,函数结构类似只是值不一样,可以提取为一个函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>字符串ref</title>
</head>
<body>
<!-- 容器 -->
<div id="test"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
// <!-- 1.创建类式组件 -->
class Login extends React.Component{
// 初始化状态
state={
username:'',
password:''
}
handlesubmit = (event)=>{
event.preventDefault()//阻止默认事件,表单的提交
const {
username,password} = this
alert(`用户名:${
this.state.username},密码:${
this.state.password}`)
}
saveFormData=(dataType)=>{
// onChange的值需要是一个回调函数,onChange回调函数的参数是event
return (event)=>{
// dataType是一个变量,作为键值时需要使用[],确保读取变量中的值
this.setState({
[dataType]: event.target.value})
}
}
render(){
return(
<form action="http://www.baidu.com" onSubmit={
this.handlesubmit} >
用户名:<input onChange={
this.saveFormData('username')} type="text" name="username"/><br/>
密码:<input onChange={
this.saveFormData('password')} type="password" name="password"/><br/>
<button>登录</button>
</form>
)
}
}
// <!--2.渲染虚拟DOM到页面 -->
ReactDOM.render(<Login/>,document.getElementById('test'))
</script>
</body>
</html>
上述代码中的saveFormData
就是一个高阶函数。
高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
- 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
- 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
常见的高阶函数有:Promise、setTimeout、 arr.map() 等
函数柯里化
函数的柯里化:通过函数调用继续返回函数
的方式,实现多次接收参数最后统一处理的函数编码形式。
上述的代码就应用了柯里化:
saveFormData=(dataType)=>{
return (event)=>{
this.setState({
[dataType]: event.target.value})
}
}