目录:
- 基本理解和使用:
- 使用React开发者工具调试
- 函数式组件
- 复习类的基本知识
- 类式组件
- 组件三大核心属性1: state
- 复习类中方法this指向:
- 复习bind函数:
- 解决changeWeather中this指向问题:
- 一般写法:state.html
- 在精简写法之前,复习一下类的基本知识:
- 精简写法:
- 组件三大核心属性2: props
- props的基本使用.html
- 复习展开运算符.html
- 使用展开运算符,批量传递props
- 对props进行限制
- props的简写方式.html
- 类式组件中的构造器与props:
- 函数式组件使用props:
- 组件三大核心属性3: refs与事件处理
- 字符串形式的ref
- 回调形式的ref
- 回调ref中调用次数的问题
- createRef的使用
- 事件处理
- 收集表单数据
- 非受控组件
- 受控组件
- 高阶函数,函数柯里化
- 高阶函数,函数柯里化
- 对象相关的知识
- 演示函数的柯里化
- 组件的生命周期
- 引出生命周期
- react生命周期(旧)
- react生命周期(l日)_setState流程
- react生命周期(l日)_forceUpdate流程
- 虚拟DOM与DOM Diffing算法
1.基本理解和使用:
使用React开发者工具调试
函数式组件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
function MyComponent() {
console.log(this)//此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
ReactDOM.render(<MyComponent></MyComponent>, document.getElementById('test'))
// 执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
// 1.React解析组件标签,找到了MyComponent组件。
// ⒉发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DON转为真实DOM,随后呈现在页面中。
</script>
</body>
</html>
运行结果:
复习类的基本知识:
总结:
- 类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时厅与。
- 如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。
- 类中所定义的方法,都是放在了类的原型对象上,供实例去使用
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
// 创建一个Person类
class Person {
//构造器方法
constructor(name, age) {
//构造器中的this是谁?—类的实例对象
this.name = name
this.age = age
this.school = '尚硅谷'
}
//一般方法
speak() {
//speak方法放在了哪里?—类的原型对象上,供实例使用
//通过Person实例调用speak时,speak中的this就是Person实例
console.log(`我叫${this.name},我年龄是${this.age}`)
}
}
//创建一个Student类,继承于Person类
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade
}
//重写从父类继承过来的方法
speak() {
console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`)
}
study() {
//study方法放在了哪里?—类的原型对象上,供实例使用
//通过student实例调用study时,study中的this就是Student实例
console.log('我很努力的学习')
}
}
const s1 = new Student('小张', 15, '高一')
console.log(s1)
s1.speak()
s1.study()
</script>
</body>
</html>
类式组件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//1.创建类式组件
class MyComponent extends React.Component {
render() {
//render是放在哪里的?-—- MyComponent的原型对象上,供实例使用。
//render中的this是谁?— MyComponent的实例对象。MyComponent组件实例对象
return <h2>我是类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>, document.getElementById('test'))
/**
* 执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
* 1.React解析组件标签,找到了MyComponent组件。
* 2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
* 3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
* */
</script>
</body>
</html>
运行结果:
2.组件三大核心属性1: state
简介:
在React中,state是一个非常重要的属性,主要用于标识组件的状态,以及更新UI,使页面动态变化。
对于state的定义和使用,主要有以下特点:
- state的值是json对象类型,可以维护多个key-value的组合。
- 在类组件中,state是组件的一个默认属性,用于存储和跟踪组件的状态。当state变化时,组件将被重新渲染。这意味着React将根据最新的state值重新计算渲染输出,并对DOM进行更新。
- 在函数组件中,由于没有对象属性(babel默认开启了局部严格模式,函数内部this指向undefined),所以没有state属性。因此,函数组件只负责展示静态页面,而不进行动态更新。
- state的值是可变的,但props的值是只读的。props属性值可以进行类型、必要性限制,也可以设置属性默认值,但组件自身不能修改props属性值。
总的来说,React的state主要用于存储和更新组件的状态,从而可以动态地控制组件的渲染和显示内容。
复习原生事件绑定:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button onclick="demo()">按钮3</button>
<script type="text/javascript">
const btn1 = document.getElementById('btn1')
btn1.addEventListener('click', () => {
alert('按钮1被点击了')
})
const btn2 = document.getElementById('btn2')
btn2.onclick = () => {
alert('按钮2被点击了')
}
function demo() {
alert('按钮3被点击了')
}
</script>
</body>
</html>
复习类中方法this指向:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
study() {
//study方法放在了哪里?—类的原型对象上,供实例使用
//通过Person实例调用study时,study中的this就是Person实例
console.log(this)
}
}
const p1 = new Person('tom', 18)
p1.study()
const x = p1.study
x()
//为了证明js自动在类中的方法上加了严格模式,this不指向window
function demo() {
console.log(this)
}
demo()
function demo1() {
'use strict'
console.log(this)
}
demo1()
</script>
</body>
</html>
复习bind函数:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
function demo() {
console.log(this)
}
demo()
const x = demo.bind({a: 1, b: 2})
x()
</script>
</body>
</html>
效果(需求: 定义一个展示天气信息的组件)
- 默认展示天气炎热 或 凉爽
- 点击文字切换天气
解决changeWeather中this指向问题:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//1.创建组件
class Weather extends React.Component {
constructor(props) {
super(props);
//初始化状态
this.state = {isHot: true}
//解决changeweather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
}
render() {
const {isHot} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>
}
changeWeather() {
//changeweather放在哪里?—— weather的原型对象上,供实例使用
//由于changeweather是作为onClick的回调,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以changeweather中的this为undefined
console.log(this)
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
一般写法:state.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//1.创建组件
class Weather extends React.Component {
//构造器调用几次? -- 1次
constructor(props) {
console.log('constructor')
super(props);
//初始化状态
this.state = {isHot: true, wind: '微风'}
//解决changeweather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
}
//render调用几次? -- 1+n次 1是初始化的那次 n是状态更新的次数
render() {
console.log('render')
const {isHot, wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//changeWeather调用几次? -- 点几次调几次
changeWeather() {
//changeweather放在哪里?—— weather的原型对象上,供实例使用
//由于changeweather是作为onClick的回调,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以changeweather中的this为undefined
// console.log(this)
console.log('changeWeather')
const isHot = this.state.isHot
//严重注意:状态(state)不可直接更改,下面这行就是直接更改!! !
// this.state.isHot = !isHot
// console.log(this.state.isHot)
// /严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot: !isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
在精简写法之前,复习一下类的基本知识:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
// 创建一个Person类
class Person {
//构造器方法
constructor(name, age) {
//构造器中的this是谁?—类的实例对象
this.name = name
this.age = age
this.school = '尚硅谷'
}
//一般方法
speak() {
//speak方法放在了哪里?—类的原型对象上,供实例使用
//通过Person实例调用speak时,speak中的this就是Person实例
console.log(`我叫${this.name},我年龄是${this.age}`)
}
}
//创建一个Student类,继承于Person类
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade
}
//重写从父类继承过来的方法
speak() {
console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`)
}
study() {
//study方法放在了哪里?—类的原型对象上,供实例使用
//通过student实例调用study时,study中的this就是Student实例
console.log('我很努力的学习')
}
}
//
// const s1 = new Student('小张', 15, '高一')
// console.log(s1)
// s1.speak()
// s1.study()
class Car {
constructor(name, price) {
this.name = name
this.price = price
}
a = 1
}
const c1 = new Car('奔驰c63', 199)
const c2 = new Car('宝马', 299)
console.log(c1)
console.log(c2)
</script>
</body>
</html>
精简写法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//1.创建组件
class Weather extends React.Component {
state = {isHot: true, wind: '微风'}
render() {
const {isHot, wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
changeWeather = () => {
const isHot = this.state.isHot
this.setState({isHot: !isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
理解
- state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
- 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
强烈注意
- 组件中render方法中的this为组件实例对象
- 组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的bind()
- 箭头函数
- 状态数据,不能直接修改或更新
3.组件三大核心属性2: props
简介:
React中的props是一种类似于JavaScript函数的组件概念,它允许组件接收任意的输入参数,并返回用于描述页面展示内容的React元素。
具体来说,props的主要作用和用途包括以下几个方面:
- 传递数据:props可以用于向子组件传递数据,这些数据可能是父组件的状态或者是其他兄弟组件的状态。通过props,子组件可以获得父组件或其他组件传递过来的数据,从而更新自己的状态。
- 外部控制:通过props,父组件可以对子组件进行控制,例如设置初始状态或者传递回调函数。这种控制方式使得React的组件之间具有更好的互动性和协作性。
- 自定义行为:通过props,我们可以向组件传递一些自定义的属性,从而改变组件的行为或者样式。例如,我们可以向按钮组件传递一个“disabled”属性,使得按钮变得不可点击。
- 属性约束:与state不同,props是只读的,也就是说子组件不能修改父组件传递过来的props数据。这使得React的组件之间具有更好的可维护性和可预测性。
总的来说,React的props是一种强大的工具,它可以使得组件之间的数据传递更加灵活和高效,同时也可以使得组件的行为更加自定义和可控。
props的基本使用.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//创建组件
class Person extends React.Component {
render() {
console.log(this)
const {name, age, sex} = this.props
return (
// <ul>
// <li>姓名:{this.props.name}</li>
// <li>性别:{this.props.sex}</li>
// <li>年龄:{this.props.age}</li>
// </ul>
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Person name="jerry" age="19" sex="男"></Person>, document.getElementById('test1'))
ReactDOM.render(<Person name="kitty" age="20" sex="女"></Person>, document.getElementById('test2'))
ReactDOM.render(<Person name="wang" age="19" sex="男"></Person>, document.getElementById('test3'))
</script>
</body>
</html>
复习展开运算符.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
let arr1 = [1, 3, 5, 7, 9]
let arr2 = [2, 4, 6, 8, 10]
console.log(...arr1)
let arr3 = [...arr1, ...arr2]
console.log(arr3)
// function sum(a, b) {
// return a + b
// }
//
// console.log(sum(1, 2))
// function sum(...numbers) {
// console.log('@', numbers)
// }
//
// console.log(sum(1, 2, 3, 4))
function sum(...numbers) {
return numbers.reduce((preValue, currentValue) => {
return preValue + currentValue
})
}
console.log(sum(1, 2, 3, 4))
//构造字面量对象时使用展开语法
let person = {name: 'tom', age: 18}
let person2 = {...person}
// console.log(...person) //报错,展开运算符不能展开对象
console.log({...person}) //不报错,多加了一个{}
person.name = 'jerry'
console.log(person2.name)
console.log(person)
//合并
let person3 = {...person, name: 'jack', address: '地球'}
console.log(person3)
</script>
</body>
</html>
使用展开运算符,批量传递props
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//创建组件
class Person extends React.Component {
render() {
console.log(this)
const {name, age, sex} = this.props
return (
// <ul>
// <li>姓名:{this.props.name}</li>
// <li>性别:{this.props.sex}</li>
// <li>年龄:{this.props.age}</li>
// </ul>
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Person name="jerry" age="19" sex="男"></Person>, document.getElementById('test1'))
ReactDOM.render(<Person name="kitty" age="20" sex="女"></Person>, document.getElementById('test2'))
const p = {name: '老刘', age: 18, sex: '女'}
console.log(...p, '@');
console.log({...p}, '@');
// ReactDOM.render(<Person name="wang" age="19" sex="男"></Person>, document.getElementById('test3'))
ReactDOM.render(<Person {...p}></Person>, document.getElementById('test3'))
</script>
</body>
</html>
对props进行限制
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Person extends React.Component {
render() {
console.log(this)
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
}
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
speak: PropTypes.func
}
//指定默认标签属性值
Person.defaultProps = {
sex: '男',
age: 18
}
//2.渲染组件到页面
ReactDOM.render(<Person name="jerry" age={19} speak={speak}></Person>, document.getElementById('test1'))
ReactDOM.render(<Person name="kitty" age={18} sex="女"></Person>, document.getElementById('test2'))
const p = {name: '老刘', age: 18, sex: '女'}
ReactDOM.render(<Person {...p}></Person>, document.getElementById('test3'))
function speak() {
console.log('我说话了')
}
</script>
</body>
</html>
props的简写方式.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Person extends React.Component {
//对标签属性进行类型,必要性的限制
static propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
speak: PropTypes.func
}
//指定默认标签属性值
static defaultProps = {
sex: '男',
age: 18
}
render() {
console.log(this)
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Person name="jerry" age={19} speak={speak}></Person>, document.getElementById('test1'))
ReactDOM.render(<Person name="kitty" age={18} sex="女"></Person>, document.getElementById('test2'))
const p = {name: '老刘', age: 18, sex: '女'}
ReactDOM.render(<Person {...p}></Person>, document.getElementById('test3'))
function speak() {
console.log('我说话了')
}
</script>
</body>
</html>
类式组件中的构造器与props:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Person extends React.Component {
//构造器是否接受props,是否传递给super,取决于:是否希望在构造器中通过this访间props
constructor(props) {
console.log(props)
super(props)
console.log('constructor', this.props)
}
//对标签属性进行类型,必要性的限制
static propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
speak: PropTypes.func
}
//指定默认标签属性值
static defaultProps = {
sex: '男',
age: 18
}
render() {
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Person name="jerry"></Person>, document.getElementById('test1'))
</script>
</body>
</html>
函数式组件使用props:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
function Person(props) {
const {name, age, sex} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{age}</li>
<li>年龄:{sex}</li>
</ul>
)
}
//对标签属性进行类型,必要性的限制
Person.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
speak: PropTypes.func
}
//指定默认标签属性值
Person.defaultProps = {
sex: '男',
age: 18
}
//2.渲染组件到页面
ReactDOM.render(<Person name="jerry"></Person>, document.getElementById('test1'))
</script>
</body>
</html>
4.组件三大核心属性3: refs与事件处理
简介:
- React中的refs属性是一种提供对真实DOM(组件)的引用的机制,通过这个引用,我们可以直接操作DOM(组件)。
- 在React中,我们通常不会直接操作底层的DOM元素,而是通过在render方法中编写页面结构,并由React来组织DOM元素的更新。然而,有些情况下,我们可能需要对页面的真实DOM进行直接操作,这时就需要用到refs。
- refs是用于访问和操作React元素(虚拟DOM元素)的一种方式。它使我们能够更加方便且准确地控制refs的设置和解除。在ref中,我们可以传递一个函数,这个函数接受React组件实例或HTML DOM元素作为参数,以使它们能在其他地方被存储和访问。
- 对于事件处理,React中的refs也提供了相应的机制。例如,我们可以使用refs来获取HTML元素并注册事件处理函数,以便在用户与页面交互时执行特定的操作。
- 总的来说,React的refs属性为我们提供了一种机制,使我们能够对React元素(虚拟DOM元素)进行直接操作,以及处理用户与页面交互的事件。
字符串形式的ref:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Demo extends React.Component {
showData = () => {
const {input1} = this.refs
alert(input1.value)
}
showData2 = () => {
const {input2} = this.refs
alert(input2.value)
}
render() {
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮提示数据"></input>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>
回调形式的ref:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Demo extends React.Component {
showData = () => {
const {input1} = this
alert(input1.value)
}
showData2 = () => {
const {input2} = this
alert(input2.value)
}
render() {
return (
<div>
<input ref={(currentNode) => {this.input1 = currentNode}} type="text" placeholder="点击按钮提示数据"></input>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input ref={(currentNode) => {this.input2 = currentNode}} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>
回调ref中调用次数的问题:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Demo extends React.Component {
state = {isHot: true}
showInfo = () => {
const {input1} = this
alert(input1.value)
}
changeWeather = () => {
const {isHot} = this.state
this.setState({isHot: !isHot})
}
saveInput = (currentNode) => {
this.input1 = currentNode;
console.log('@', currentNode);
}
render() {
const {isHot} = this.state
return (
<div>
<h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
<br></br>
{/*<input ref={(currentNode) => {this.input1 = currentNode;console.log('@', currentNode);}} type="text"></input>*/}
<input ref={this.saveInput} type="text"></input>
<br></br>
<button onClick={this.showInfo}>点我提示输入的数据</button>
<button onClick={this.changeWeather}>点我切换天气</button>
<br></br>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Demo></Demo>, document.getElementById('test'))
</script>
</body>
</html>
createRef的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Demo extends React.Component {
// React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
myRef = React.createRef()
myRef2 = React.createRef()
showData = () => {
alert(this.myRef.current.value)
}
showData2 = () => {
alert(this.myRef2.current.value)
}
render() {
return (
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"></input>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input ref={this.myRef2} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>
事件处理
- 1.通过onXxx属性指定事件处理函数(注意大小写)
- a.React使用的是自定义(合成)事件,而不是使用的原生DOM事件 ----- 为了更好的兼容性
- b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ----- 为了高效
- 2.通过event.target得到发生事件的DOM元素对象-不要过度使用ref
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Demo extends React.Component {
// React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
myRef = React.createRef()
myRef2 = React.createRef()
showData = (event) => {
console.log(event, 'showData event')
console.log(event.target.value)
console.log(this.myRef.current.value)
alert(this.myRef.current.value)
}
showData2 = (event) => {
console.log(event, 'showData2 event')
alert(event.target.value)
}
render() {
return (
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"></input>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>
5.收集表单数据
非受控组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Login extends React.Component {
handleSubmit = (event) => {
event.preventDefault()
const {username, password} = this
alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input ref={c => this.username = c} type="text" name="username"></input>
密码:<input ref={c => this.password = c} type="password" name="password"></input>
<button>登录</button>
</form>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Login></Login>, document.getElementById('test'))
</script>
</body>
</html>
受控组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Login extends React.Component {
state = {
username: '',
password: ''
}
saveUsername = (event) => {
this.setState({username: event.target.value})
}
savePassword = (event) => {
this.setState({password: event.target.value})
}
handleSubmit = (event) => {
event.preventDefault()
const {username, password} = this.state
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} type="text" name="username"></input>
密码:<input onChange={this.savePassword} type="password" name="password"></input>
<button>登录</button>
</form>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Login></Login>, document.getElementById('test'))
</script>
</body>
</html>
6.高阶函数,函数柯里化
高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
- 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
- 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
- 常见的高阶函数有:Promise、setTimeout、arr.map()等等
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。
高阶函数,函数柯里化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Login extends React.Component {
state = {
username: '',
password: ''
}
saveFormData = (dateType) => {
return (event) => {
this.setState({[dateType]: event.target.value})
}
}
handleSubmit = (event) => {
event.preventDefault()
const {username, password} = this.state
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveFormData('username')} type="text" name="username"></input>
密码:<input onChange={this.saveFormData('password')} type="password" name="password"></input>
<button>登录</button>
</form>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Login></Login>, document.getElementById('test'))
</script>
</body>
</html>
对象相关的知识
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
let a = 'name'
let obj = {}
obj[a] = 'tom'
console.log(obj)
</script>
</body>
</html>
演示函数的柯里化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
// function sum(a, b, c) {
// return a + b + c
// }
//
// const result = sum(1, 2, 3)
// console.log(result)
function sum(a) {
return (b) => {
return (c) => {
return a + b + c
}
}
}
const result = sum(1)(2)(3)
console.log(result)
</script>
</body>
</html>
7.组件的生命周期
引出生命周期:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Life extends React.Component {
state = {opacity: 1}
death = () => {
clearInterval(this.timer)
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//组件挂载完毕
componentDidMount() {
console.log('组件挂载完毕')
this.timer = setInterval(() => {
let {opacity} = this.state
opacity -= 0.1
if (opacity <= 0) opacity = 1
this.setState({opacity})
}, 200)
}
//组件将要卸载
componentWillUnmount() {
console.log('组件将要卸载')
clearInterval(this.timer)
}
//初始化渲染、状态更新之后
render() {
console.log('render')
return (
<div>
<h2 style={{opacity: this.state.opacity}}>React学不会怎么办?</h2>
<button onClick={this.death}>不活了</button>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Life></Life>, document.getElementById('test'))
</script>
</body>
</html>
react生命周期(旧)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Count extends React.Component {
constructor(props) {
console.log('Count---constructor')
super(props);
this.state = {count: 0}
}
state = {count: 0}
add = () => {
const {count} = this.state
this.setState({count: count + 1})
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
componentWillMount() {
console.log('Count---componentWillMount')
}
componentDidMount() {
console.log('Count---componentDidMount')
}
componentWillUnmount() {
console.log('Count---componentWillUnmount')
}
render() {
console.log('Count---render')
const {count} = this.state
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>
react生命周期(l日)_setState流程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>
<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Count extends React.Component {
constructor(props) {
console.log('Count---constructor')
super(props);
this.state = {count: 0}
}
state = {count: 0}
add = () => {
const {count} = this.state
this.setState({count: count + 1})
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
componentWillMount() {
console.log('Count---componentWillMount')
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log('Count---componentDidMount')
}
// 组件将要卸载的钩子
componentWillUnmount() {
console.log('Count---componentWillUnmount')
}
//控制组件更新的“阀门”
shouldComponentUpdate() {
console.log('Count---shouldComponentUpdate')
return true
}
//组件将要更新的钩子
componentWillUpdate() {
console.log('Count---componentWillUpdate')
}
//组件更新完毕的钩子
componentDidUpdate() {
console.log('Count---componentDidUpdate')
}
render() {
console.log('Count---render')
const {count} = this.state
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
</div>
)
}
}
//2.渲染组件到页面
ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>
react生命周期(l日)_forceUpdate流程