[尚硅谷React笔记]——第2章 React面向组件编程
目录:
- 基本理解和使用:
- 使用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流程
- react生命周期(l日)_父组件render流程
- react新生命周期
- react生命周期(新)_getDerivedStateFromProps
- react生命周期(新)_getSnapshotBeforeUpdate
- react生命周期(新)_getSnapshotBeforeUpdate的使用场景
- 虚拟DOM与DOM Diffing算法
- 验证Diffing算法
- key的作用
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 = namethis.age = agethis.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 = namethis.age = age}study() {//study方法放在了哪里?—类的原型对象上,供实例使用//通过Person实例调用study时,study中的this就是Person实例console.log(this)}}const p1 = new Person('tom', 18)p1.study()const x = p1.studyx()//为了证明js自动在类中的方法上加了严格模式,this不指向windowfunction 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.statereturn <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>}changeWeather() {//changeweather放在哪里?—— weather的原型对象上,供实例使用//由于changeweather是作为onClick的回调,所以不是通过实例调用的,是直接调用//类中的方法默认开启了局部的严格模式,所以changeweather中的this为undefinedconsole.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.statereturn <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 = namethis.age = agethis.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 = namethis.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.statereturn <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>}changeWeather = () => {const isHot = this.state.isHotthis.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.propsreturn (// <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.propsreturn (// <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.propsreturn (<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.propsreturn (<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访间propsconstructor(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.propsreturn (<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} = propsreturn (<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.refsalert(input1.value)}showData2 = () => {const {input2} = this.refsalert(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} = thisalert(input1.value)}showData2 = () => {const {input2} = thisalert(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} = thisalert(input1.value)}changeWeather = () => {const {isHot} = this.statethis.setState({isHot: !isHot})}saveInput = (currentNode) => {this.input1 = currentNode;console.log('@', currentNode);}render() {const {isHot} = this.statereturn (<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} = thisalert(`你输入的用户名是:${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.statealert(`你输入的用户名是:${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.statealert(`你输入的用户名是:${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.组件的生命周期
生命周期的三个阶段(旧)
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
- constructor()
- componentWillMount()
- render()
- componentDidMount()
- 更新阶段: 由组件内部this.setSate()或父组件重新render触发
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()
引出生命周期:
<!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.stateopacity -= 0.1if (opacity <= 0) opacity = 1this.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.statethis.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.statereturn (<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.statethis.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.statereturn (<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流程
<!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.statethis.setState({count: count + 1})}death = () => {ReactDOM.unmountComponentAtNode(document.getElementById('test'))}force = () => {this.forceUpdate()}//组件将要挂载的钩子componentWillMount() {console.log('Count---componentWillMount')}// 组件挂载完毕的钩子componentDidMount() {console.log('Count---componentDidMount')}// 组件将要卸载的钩子componentWillUnmount() {console.log('Count---componentWillUnmount')}//控制组件更新的“阀门”shouldComponentUpdate() {console.log('Count---shouldComponentUpdate')return false}//组件将要更新的钩子componentWillUpdate() {console.log('Count---componentWillUpdate')}//组件更新完毕的钩子componentDidUpdate() {console.log('Count---componentDidUpdate')}render() {console.log('Count---render')const {count} = this.statereturn (<div><h2>当前求和为:{count}</h2><button onClick={this.add}>点我+1</button><button onClick={this.death}>卸载组件</button><button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button></div>)}}//2.渲染组件到页面ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>
react生命周期(l日)_父组件render流程
<!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 A extends React.Component {state = {carName: '奔驰'}changeCar = () => {this.setState({carName: '奥迪'})}render() {return (<div><div>A</div><button onClick={this.changeCar}>换车</button><B carName={this.state.carName}></B></div>)}}class B extends React.Component {componentWillReceiveProps(props) {console.log('B---componentWillReceiveProps', props)}shouldComponentUpdate() {console.log('B---sholdComponentUpdate')return true}componentWillUpdate() {console.log('B---componentWillUpdate')}componentDidUpdate() {console.log('B---componentDidUpdate')}render() {console.log('B---render')return (<div>我是B组件,接收到的车是:{this.props.carName}</div>)}}//2.渲染组件到页面ReactDOM.render(<A></A>, document.getElementById('test'))
</script>
</body>
</html>
react新生命周期
生命周期的三个阶段(新)
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
- constructor()
- getDerivedStateFromProps
- render()
- componentDidMount()
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
- getDerivedStateFromProps
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate
- componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()
重要的勾子
- render:初始化渲染或更新渲染调用
- componentDidMount:开启监听, 发送ajax请求
- componentWillUnmount:做一些收尾工作, 如: 清理定时器
即将废弃的勾子
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。
<!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="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script><script type="text/javascript" src="../newjs/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.statethis.setState({count: count + 1})}death = () => {ReactDOM.unmountComponentAtNode(document.getElementById('test'))}force = () => {this.forceUpdate()}//组件将要挂载的钩子UNSAFE_componentWillMount() {console.log('Count---UNSAFE_componentWillMount')}// 组件挂载完毕的钩子componentDidMount() {console.log('Count---componentDidMount')}// 组件将要卸载的钩子componentWillUnmount() {console.log('Count---componentWillUnmount')}//控制组件更新的“阀门”shouldComponentUpdate() {console.log('Count---shouldComponentUpdate')return false}//组件将要更新的钩子UNSAFE_componentWillUpdate() {console.log('Count---UNSAFE_componentWillUpdate')}//组件更新完毕的钩子componentDidUpdate() {console.log('Count---componentDidUpdate')}render() {console.log('Count---render')const {count} = this.statereturn (<div><h2>当前求和为:{count}</h2><button onClick={this.add}>点我+1</button><button onClick={this.death}>卸载组件</button><button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button></div>)}}class A extends React.Component {state = {carName: '奔驰'}changeCar = () => {this.setState({carName: '奥迪'})}render() {return (<div><div>A</div><button onClick={this.changeCar}>换车</button><B carName={this.state.carName}></B></div>)}}class B extends React.Component {UNSAFE_componentWillReceiveProps(props) {console.log('B---componentWillReceiveProps', props)}shouldComponentUpdate() {console.log('B---sholdComponentUpdate')return true}UNSAFE_componentWillUpdate() {console.log('B---UNSAFE_componentWillUpdate')}componentDidUpdate() {console.log('B---componentDidUpdate')}render() {console.log('B---render')return (<div>我是B组件,接收到的车是:{this.props.carName}</div>)}}//2.渲染组件到页面ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>
react生命周期(新)_getDerivedStateFromProps
<!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="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script><script type="text/javascript" src="../newjs/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.statethis.setState({count: count + 1})}death = () => {ReactDOM.unmountComponentAtNode(document.getElementById('test'))}force = () => {this.forceUpdate()}static getDerivedStateFromProps(props, state) {console.log('Count---getDerivedStateFromProps', props, state)return props}// 组件挂载完毕的钩子componentDidMount() {console.log('Count---componentDidMount')}// 组件将要卸载的钩子componentWillUnmount() {console.log('Count---componentWillUnmount')}//控制组件更新的“阀门”shouldComponentUpdate() {console.log('Count---shouldComponentUpdate')return true}//组件更新完毕的钩子componentDidUpdate() {console.log('Count---componentDidUpdate')}render() {console.log('Count---render')const {count} = this.statereturn (<div><h2>当前求和为:{count}</h2><button onClick={this.add}>点我+1</button><button onClick={this.death}>卸载组件</button><button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button></div>)}}//2.渲染组件到页面ReactDOM.render(<Count count={199}></Count>, document.getElementById('test'))
</script>
</body>
</html>
react生命周期(新)_getSnapshotBeforeUpdate
<!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="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script><script type="text/javascript" src="../newjs/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.statethis.setState({count: count + 1})}death = () => {ReactDOM.unmountComponentAtNode(document.getElementById('test'))}force = () => {this.forceUpdate()}static getDerivedStateFromProps(props, state) {console.log('Count---getDerivedStateFromProps', props, state)return null}getSnapshotBeforeUpdate() {console.log('Count---getSnapshotBeforeUpdate')return 'atguigu'}// 组件挂载完毕的钩子componentDidMount() {console.log('Count---componentDidMount')}// 组件将要卸载的钩子componentWillUnmount() {console.log('Count---componentWillUnmount')}//控制组件更新的“阀门”shouldComponentUpdate() {console.log('Count---shouldComponentUpdate')return true}//组件更新完毕的钩子componentDidUpdate(preProps, preState, snapshotValue) {console.log('Count---componentDidUpdate', preProps, preState, snapshotValue)}render() {console.log('Count---render')const {count} = this.statereturn (<div><h2>当前求和为:{count}</h2><button onClick={this.add}>点我+1</button><button onClick={this.death}>卸载组件</button><button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button></div>)}}//2.渲染组件到页面ReactDOM.render(<Count count={199}></Count>, document.getElementById('test'))
</script>
</body>
</html>
react生命周期(新)_getSnapshotBeforeUpdate的使用场景
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.list {width: 200px;height: 150px;background-color: skyblue;overflow: auto;}.news {height: 30px;}</style>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div><!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script><script type="text/javascript" src="../newjs/prop-types.js"></script><script type="text/babel">class NewsList extends React.Component {state = {newsArr: []}componentDidMount() {setInterval(() => {const {newsArr} = this.stateconst news = '新闻' + (newsArr.length + 1)this.setState({newsArr: [news, ...newsArr]})}, 1000)}getSnapshotBeforeUpdate() {return this.refs.list.scrollHeight}componentDidUpdate(preProps,preState,height){this.refs.list.scrollTop += this.refs.list.scrollHeight - height}render() {return (<div className="list" ref="list">{this.state.newsArr.map((n, index) => {return <div key={index} className="news">{n}</div>})}</div>)}}//2.渲染组件到页面ReactDOM.render(<NewsList></NewsList>, document.getElementById('test'))
</script>
</body>
</html>
8.虚拟DOM与DOM Diffing算法
- 虚拟DOM中key的作用:
- 简单的说: key是虚拟DOA对象的标识,在更新显示时key起着极其重要的作用。
- 详细的说:当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】 ,随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下;
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
- 若虚拟DOM中内容没变,直接使用之前的真实DOM
- 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
- 旧虚拟DOM中未找到与新虚拟DOM相同的key根据数据创建新的真实DOM,随后渲染到到页面
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
- 用index作为key可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新· ==>·界面效果没问题,但效率低。
- 如果结构中还包含输入类的DOM:会产生错误DOM更新==>界面有问题。
- 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
- 开发中如何选择key? :
- 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
- 如果确定只是简单的展示数据,用index也是可以的。
验证Diffing算法
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.list {width: 200px;height: 150px;background-color: skyblue;overflow: auto;}.news {height: 30px;}</style>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div><!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script><script type="text/javascript" src="../newjs/prop-types.js"></script><script type="text/babel">class Time extends React.Component {state = {date: new Date()}componentDidMount() {setInterval(() => {this.setState({date: new Date()})},1000)}render() {return (<div><h1>hello</h1><input type="text"></input><span>现在是:{this.state.date.toTimeString()}</span></div>);}}//2.渲染组件到页面ReactDOM.render(<Time></Time>, document.getElementById('test'))
</script>
</body>
</html>
key的作用
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.list {width: 200px;height: 150px;background-color: skyblue;overflow: auto;}.news {height: 30px;}</style>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div><!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script><script type="text/javascript" src="../newjs/prop-types.js"></script><script type="text/babel">// 慢动作回放----使用index索引值做为key// 初始数据:// {id:1,name:'小张',age:18},// {id:2,name:'小李',age:19},// 初始的虚拟DOM:// <li key=0>小张---18</li>// <li key=1>小李---19</li>// 更新后的数据:// {id:3,name:'小王',age:20},// {id:1,name:'小张',age:18},// {id:2,name:"小李',age:19},// "更新数据后的虚拟DOM:// <li key=0>小王---20</li>// <li key=1>小张---18</li>// <li key=2>小李---19</li>// ---------------------------------------------------// 慢动作回放----使用id唯一标识做为key// 初始数据:// {id:1,name:'小张',age:18},// {id:2,name:'小李',age:19},// 初始的虚拟DOM:// <li key=1>小张---18</li>// <li key=2>小李---19</li>// 更新后的数据:// {id:3,name:'小王',age:20},// {id:1,name:'小张',age:18},// {id:2,name:"小李',age:19},// "更新数据后的虚拟DOM:// <li key=3>小王---20</li>// <li key=1>小张---18</li>// <li key=2>小李---19</li>class Person extends React.Component {state = {persons: [{id: 1, name: '小张', age: 18},{id: 2, name: '小李', age: 19},]}add = () => {const {persons} = this.stateconst p = {id: persons.length + 1, name: '小王', age: 20}this.setState({persons: [p, ...persons]})}render() {return (<div><h2>展示人员信息</h2><button onClick={this.add}>添加一个小王</button><h3>使用index索引值作为key</h3><ul>{this.state.persons.map((personObj, index) => {return <li key={index}>{personObj.name}---{personObj.age}<input type="text"></input></li>})}</ul><hr></hr><hr></hr><h3>使用id(数据的唯一标识)作为key</h3><ul>{this.state.persons.map((personObj) => {return <li key={personObj.id}>{personObj.name}---{personObj.age}<input type="text"></input></li>})}</ul></div>);}}//2.渲染组件到页面ReactDOM.render(<Person></Person>, document.getElementById('test'))
</script>
</body>
</html>
运行结果:
相关文章:
[尚硅谷React笔记]——第2章 React面向组件编程
目录: 基本理解和使用: 使用React开发者工具调试函数式组件复习类的基本知识类式组件组件三大核心属性1: state 复习类中方法this指向: 复习bind函数:解决changeWeather中this指向问题:一般写法:state.htm…...
嵌入式学习笔记(40)看门狗定时器
7.5.1什么是看门狗、有何用 (1)看门狗定时器和普通定时器并无本质区别。定时器可以设定一个时间,在这个时间完成之前定时器不断计时,时间到的时候定时器会复位CPU(重启系统)。 (2)系统正常工作的时候当然不希望被重启࿰…...
点击、拖拉拽,BI系统让业务掌握数据分析主动权
在今天的商业环境中,数据分析已经成为企业获取竞争优势的关键因素之一。然而,许多企业在面对复杂的数据分析工具时,却常常感到困扰。这些工具往往需要专业的技术人员操作,而且界面复杂,难以理解和使用。对业务人员来说…...
C++模拟题[第一周-T1] 扑克
[第一周-T1] 扑克 题目描述 斗地主是一种使用 A \tt A A 到 K \tt K K 加上大小王的共 54 54 54 张扑克牌来进行的游戏,其中大小王各一张,其它数码牌各四张。在斗地主中,牌的大小关系根据牌的数码表示如下: 3 < 4 < 5 …...
ciscn_2019_s_9
ciscn_2019_s_9 Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments32位,啥也没开,开心愉悦写shellcode int pwn() {char s[24]; // [esp8…...
微信、支付宝、百度、抖音开放平台第三方代小程序开发总结
大家好,我是小悟 小伙伴们都开启小长假了吧,值此中秋国庆双节之际,小悟祝所有的小伙伴们节日快乐。 支付宝社区很用心,还特意给寄了袋月饼,愿中秋节的圆月带给你身体健康,幸福团圆,国庆节的旗帜…...
C语言协程
协程(Coroutine)是一种程序运行方式,相比于线程和进程,协程更加轻量级,可以被视为一种用户态的线程,不需要内核的参与。 协程的特点在于其执行过程中可以被挂起(Suspend)࿰…...
RK3588安装python3.11(ubuntu18.04)
1.前言 看到rknn_toolkit_lite2更新了python3.11的安装包,马上更新一下 2.RK3588安装python3.11 Ubuntu上编译Python 3.11,您可以按照以下步骤进行操作: (1) 准备编译环境 在开始之前,确保您的系统已安装必要的编译工具和依赖项…...
‘Could not find first log file name in binary log index file‘的解决办法
mysql主从报异常Got fatal error 1236 from master when reading data from binary log: Could not find first log file name in binary log index file 数据库主从出错: Slave_IO_Running: No 一方面原因是因为网络通信的问题也有可能是日志读取错误的问题。以下是日志出错…...
快速排序与冒泡排序以及代码
快速排序 快速排序(Quicksort)是一种常用的排序算法,它基于分治的思想。 时间复杂度:O(nlogn) 空间复杂度:O(logn) 快速排序的基本思想如下: 选择一个元素…...
[React] 性能优化相关 (一)
文章目录 1.React.memo2.useMemo3.useCallback4.useTransition5.useDeferredValue 1.React.memo 当父组件被重新渲染的时候,也会触发子组件的重新渲染,这样就多出了无意义的性能开销。如果子组件的状态没有发生变化,则子组件是不需要被重新渲…...
云中网络的隔离GREVXLAN
底层的物理网络设备组成的网络我们称为 Underlay 网络,而用于虚拟机和云中的这些技术组成的网络称为 Overlay 网络,这是一种基于物理网络的虚拟化网络实现。 第一个技术是 GRE,全称 Generic Routing Encapsulation,它是一种 IP-o…...
【【萌新的RiscV学习之流水线控制-9】】
萌新的RiscV学习之流水线控制-9 我们按照在之前的单周期设计加入控制单元 那么我们能够在后续的设计中提供方便 我们也在流水线中加入一个control单元 我们先按照书上的指令op码值介绍一遍基本功能 接下来我们讲述control 的 控制效果 关于这些串口判别的使用 由于控制线从…...
MySQL 通过存储过程高效插入100w条数据
目录 一、前言二、创建表三、编写存储过程插入数据四、高效插入数据方案4.1、插入数据时删除表中全部索引4.2、存储过程中使用统一事务插入(性能显著提升)4.3、调整MySQL系统配置(性能显著提升,适合存储过程没有使用统一事务&…...
国庆10.1
用select实现服务器并发 ser #include <myhead.h> #define ERR_MSG(msg) do{\fprintf(stderr, "__%d__", __LINE__);\perror(msg);\ }while(0)#define PORT 8888 //端口号,范围1024~49151 #define IP "192.168.1.205" //本机…...
[C++_containers]10分钟让你掌握vector
前言 在一个容器的创建或是使用之前,我们应该先明白这个容器的一些特征。 我们可以通过文档来来了解,当然我也会将重要的部分写在下面。 1. vector 是表示可变大小数组的序列容器。 2. 就像数组一样, vector 也采用的连续存储空间来存储元…...
前端与后端:程序中两个不同的领域
前端和后端是构成一个完整的计算机应用系统的两个主要部分。它们分别负责不同的功能和任务,有以下几个方面的区别: 功能:前端主要负责用户界面的呈现和交互,包括网页的设计、布局、样式、动画效果和用户输入等。后端则处理网站或应…...
vue3 +elementplus | vue2+elementui 动态地通过验证规则子新增或删除单个表单字段
效果图 点击 ‘’ 新增一行,点击‘-’ 删除一行 vue3elementplus写法 template <el-dialog v-model"dialogFormVisible" :title"title"><el-form ref"ruleFormRef" :model"form" :inline"true" lab…...
STM32之DMA
简介 • DMA ( Direct Memory Access )直接存储器存取 (可以直接访问STM32内部存储器,如SRAM、程序存储器Flash和寄存器等) •DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预&a…...
解决前端二进制流下载的文件(例如:excel)打不开的问题
1. 现在后端请求数据后,返回了一个二进制的数据,我们要把它下载下来。 这是响应的数据: 2. 这是调用接口的地方: uploadOk(){if(this.files.length 0){return this.$Message.warning("请选择上传文件!ÿ…...
动态规划算法(1)--矩阵连乘和凸多边形剖分
目录 一、动态数组 1、创建动态数组 2、添加元素 3、删除修改元素 4、访问元素 5、返回数组长度 6、for each遍历数组 二、输入多个数字 1、正则表达式 2、has.next()方法 三、矩阵连乘 1、什么是矩阵连乘? 2、动态规划思路 3、手推m和s矩阵 4、完…...
通过Nginx重新认识HTTP错误码
文章目录 概要一、HTTP错误码1.1、1xx1.2、2xx1.3、3xx1.4、4xx1.5、5xx 二、Nginx对常见错误处理三、参考资料 概要 在web开发过程中,通过HTTP错误码快速定位问题是一个非常重要的技能,同时Nginx是非常常用的一个实现HTTP协议的服务,因此本…...
某房产网站登录RSA加密分析
文章目录 1. 写在前面2. 抓包分析3. 扣加密代码4. 还原加密 1. 写在前面 今天是国庆节,首先祝福看到这篇文章的每一个人节日快乐!假期会老的这些天一直在忙事情跟日常带娃,抽不出一点时间来写东西。夜深了、娃也睡了。最近湖南开始降温了&…...
深度学习:基于长短时记忆网络LSTM实现情感分析
目录 1 LSTM网络介绍 1.1 LSTM概述 1.2 LSTM网络结构 1.3 LSTM门机制 1.4 双向LSTM 2 Pytorch LSTM输入输出 2.1 LSTM参数 2.2 LSTM输入 2.3 LSTM输出 2.4 隐藏层状态初始化 3 基于LSTM实现情感分析 3.1 情感分析介绍 3.2 数据集介绍 3.3 基于pytorch的代码实现 3…...
selenium使用已经获取的cookies登录网站报错unable to set cookie的处理方式
用selenium半手动登录github获取其登录cookies后,保存到一个文件gtb_cookies.txt中。 然后用selenium使用这个cookies文件,免登录上github。但是报错如下:selenium.common.exceptions.UnableToSetCookieException: Message: unable to set co…...
初阶数据结构(四)带头双向链表
💓博主csdn个人主页:小小unicorn ⏩专栏分类:数据结构 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 带头双向链表 链表的相关介绍初始化链表销毁链…...
2022年9月及10月
9月 1.Halcon12的HObject和Hobject halcon12 可以用HObject,也可以用Hobject,用法都一样 包括HalconCpp.h 如果附加目录中: C:\Program Files\MVTec\HALCON-12.0\include\halconcpp\ 在前面,则用 HalconCpp::HObject 如果附加目录…...
Vmware安装
title: “Vmware安装” createTime: 2021-11-22T09:53:2908:00 updateTime: 2021-11-22T09:53:2908:00 draft: false author: “name” tags: [“VMware”,“安装”,“linux”] categories: [“install”] description: “测试的” linux安装VMware Workstation16 1.安装包 …...
RSA算法
算法简介 RSA是一种非对称加密方式。发送者把明文通过公钥加密后发送出去,接受者把密文通过私钥解密得到明文。 算法过程 生成公钥和私钥 选取两个质数p和q,np*q。n的长度就是密钥长度。φ(n)(p-1)*(q-1)φ(n)为n的欧拉函数。找到1-φ(n)间与φ(n)互质的…...
计算机竞赛 深度学习手势识别 - yolo python opencv cnn 机器视觉
文章目录 0 前言1 课题背景2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存 5 模型训练5.1 修…...
wordpress怎么中文/seo技术培训茂名
前言:最近,手机市场上出现了许多孪生手机或者情侣手机新品,其中较有代表性的如诺基亚N97和N97 Mini,HTC HD和HTC HD Mini,它们都是外观上缩小一圈的纯粹Mini版本。另外还有如HTC钻石系列,它们是相同体积下的…...
佛山市建设小学网站/网络营销优化培训
IIS最近有个别客户反映购买的在线人数(IIS连接数)和实际不符合,现在特说明如下首先了解什么是IIS连接数。IIS连接数指并发连接数,什么意思呢?要分几种情况:(以100M空间50人在线为例)A 用户单点下载你的文件,结束后正常…...
做瞹瞹嗳视频网站在线观看/网络营销招聘岗位有哪些
夜光序言: 即使身边满是凄荒、冷淡与麻木,风也会吹得柔和,心也能寻得一份温存 正文:接下来~~,实战项目:一个拥有答题页面的微信小程序 上图为实际效果图 那么如何制作出来呢~ 点击“开始测试”按钮&#x…...
网站制作建设是做什么/十大骗子教育培训机构
文章目录 前言I 使用catchTouchPoint 函数实现点坐标的获取II 使用iOS API获取在屏幕上的点击坐标2.1 创建`UIApplication` 子类,实现`sendEvent:`获取在屏幕上的点击坐标2.2 在main方法添加principalClassNamesee also前言 获取屏幕坐标的方式: LUA 函数touchDown(idx, x, …...
wordpress 不提示更新/我想做百度推广
如果需要保持之前的顺序,使用Set中的LinkedHashSet就是有序的 对象重复是指对象里面的变量的值都相等,并不定是地址。list集合存储的类型是基础类型还比较好办,直接把list集合转换成set集合就会自动去除。 当set集合存储的是对象类型时&…...
动态ip可以做网站/软件开发公司
作用域和链接描述了标识符的可见性。存储期描述了通过这些标识符访问的对象的生存期。 C对象有4种存储期:静态存储期、线程存储期、自动存储期、动态分配存储期。 如果对象具有静态存储期,那么它在程序的执行期间一直存在。文件作用域变量具有静态存储…...