【react-笔记】

news/2024/5/20 1:09:41/文章来源:https://blog.csdn.net/weixin_47416539/article/details/127401447

目录

    • 简介
    • 基本使用
      • 虚拟dom的两种创建方法
      • jsx语法规则
    • 模块与组件、模块化和组件化的理解
      • 模块
      • 组件
      • 模块化
      • 组件化
        • 函数式组件
        • 类式组件
      • 组件实例三大属性
        • state
        • props
        • refs
    • 事件处理
    • 包含表单的组件分类
      • 非受控组件
      • 受控组件
    • 高阶函数_函数的柯里化
    • 生命周期
      • 引出生命周期
        • 理解
        • 生命周期(旧)
      • 总结
      • 新的生命周期
        • 对比旧的生命周期
        • 新的生命周期
      • 总结
    • DOM的diffing算法

简介

  1. react是什么?
    react是用于构建用户界面的js库(是一个将数据渲染为html视图的开源js库)
  2. 谁开发的?
    在这里插入图片描述
  3. 为什么要学?
    1. 原生js操作dom繁琐、效率低(DOM-API操作UI)
    2. 使用js直接操作dom,浏览器会进行大量的重绘重排
    3. 原生js没有组件化编码方案,代码复用率低
  4. react的特点
    1. 才用组件化模式、声明式编码,提高开发效率及组件复用率
    2. 在ReactNative中可以使用react语法进行移动端开发
    3. 使用虚拟dom+优秀的diffing算法,尽量减少与真实DOM的交互

基本使用

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">/*注意:此处一定要写babel*///1.创建虚拟DOMconst VDOM = (<h1 id="title"><span>hello react</span></h1>)/*注意:此处一定不要写引号,因为不是字符串*///2.渲染虚拟DOM到页面ReactDOM.render(VDOM,document.getElementById('app'))/*注意:如果下面还有一模一样的这句话则是覆盖不是追加*/
</script>
</html>

虚拟dom的两种创建方法

  1. jsx (基本使用的写法)
  2. js (一般不用)
<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</body>
<script type="text/javascript">//1.创建虚拟DOMconst VDOM = React.createElement('h1',{id:'title'},'hello react')//2.渲染虚拟DOM到页面ReactDOM.render(VDOM,document.getElementById('app'))
</script>
</html>

关于虚拟DOM:

  1. 本质是Object类型的对象(一般对象)
  2. 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部再用,无需真实DOM上那么多的属性(轻重指的是身上所有的方法和属性多与少)
  3. 虚拟DOM最终会被React转化为真实DOM,呈现在页面上
    (debugger-浏览器打断点)

jsx语法规则

介绍jsx

  1. 全称:JavaScript XML
  2. react定义的一种类似于XML的JS扩张语法:JS+XML
  3. 作用:
    1. 写法:var ele = <h1>hello react</h1>
    2. 注意1. 他不是字符串,也不是HTML/XML标签
    3. 注意2. 他最终产生的就是一个JS对象
  4. 标签名任意:HTML标签或其他标签
    jsx语法规则
  5. 定义虚拟DOM时,不要写引号。
  6. 标签中混入js表达式要用{}
  7. 样式的类名指定不要用class,要用className
  8. 内联样式,要用style={{key:value}}的形式去写(第一个{}:是jsx语法,第二个{}是键值对的写法)
  9. 只有一个跟标签
  10. 标签必须闭合
  11. 标签首字母
    1. 若小写字母开头,则将改标签转为html中同名元素,若html中无该标签对应的同名元素,则报错
    2. 若大写字母开头,react就去渲染对应的组件。若组件没有定义,则报错
<script type="text/babel">let data = 'hello react'let dataClsaa='list'let arr = ['vue','react','juqery']//1.创建虚拟DOMconst VDOM = (<div className={dataClsaa}><h2 style={{color:'red'}}>{data}</h2>    <input type="text"/><ul>/*遍历的时候必须要有个key*/{data.map((item,index)=>{return <li key={index}>{item}</li>})}</ul></div>)//2.渲染虚拟DOM到页面ReactDOM.render(VDOM,document.getElementById('app'))</script>

注意区分:【js语句(代码)】与【js表达式】

  1. 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
    下面这些都是表达式:1. a 2. a+b 3. demo(1) 4. arr.map() 5. function test(){}
  2. 语句(代码)
    下面这些都是语句(代码)1. if(){} 2. for(){} 3. switch*(){case:xx}

模块与组件、模块化和组件化的理解

模块

  1. 理解:向外提供俱特定功能的js程序,一般就是一个js文件
  2. 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂
  3. 作用:复用js,简化js的编写,提高js运行效率

组件

  1. 理解:用来实现局部功能效果的代码和资源的集合
  2. 为什么:一个界面的功能更复杂
  3. 作用:复用编码,简化项目编码,提高运行效率

模块化

当应用的js都以模块来编写的,这个应用就是一个模块化应用

组件化

当应用是以组件的方式实现,这个应用就是一个组件化的应用

函数式组件

(简单组件):无状态{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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建函数式组件function Demo(){/*1.函数名首字母要大写2.函数必须有返回值*/console.log(this)//this是undefined(因为babel是严格模式,导致自定义组件的this不指向window)return <h2>hello react</h2>}//2.渲染组件到页面ReactDOM.render(<Demo/>,document.getElementById('app'))/*第一个参要写闭合的组件*//*执行了ReactDOM.render(<Demo/>,document.getElementById('app'))之后发生了什么?1.React解析组件标签,找到了Demo组件(找不见就会报错)2.发现组件是使用函数定义的,税后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中*/
</script>
</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>Document</title>
</head>
<body></body>
<script type="text/javascript">//常见一个Person类class Person{//构造器方法constructor(name,age){//构造器中的this是谁?——类的实例对象this.name = namethis.age = age}//类中可以直接写赋值语句a=2//一般方法:除了构造器的方法,程序员根据业务需求写的方法称之为一般方法speak(){//speak方法放在哪里?——类的原型对象上,供实例使用//通过Person实例调用speak时,speak中的this就是Person实例console.log(`我叫${this.name},我的年龄是${this.age}`)}}// const p1 = new Person('tom',18)// const p2 = new Person('jerry',19)// console.log(p1,p2)//创建一个student类,继承于person类class Student extends Person{constructor(name,age,grade){super(name,age)//继承父级-必须在最开始的时候调用super()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)/*总结:1. 类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时才写2. 如果a类继承了b类,且a类中写了构造器,那么a类构造器中的super是必须要调用的3. 类中所定义的方法,都是放在了类的原型对象上,供实例去使用*/
</script>
</html>

组件实例三大属性

state

类式组件
(复杂组件):有状态{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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{//render是放在哪里的?——类的原型对象上,供实例使用//render中的this是谁?——MyComponent的实例对象<=>(MyComponent组件实例对象)render(){console.log(this)return <h2>hello react——简单组件(无状态)</h2>}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))/*第一个参要写闭合的组件*//*执行了 ReactDOM.render(<MyComponent/>,document.getElementById('app'))之后,发生了什么?1.react解析组件标签,找到了MyComponent组件2.发现组件是使用类定义的,税后new出来该类的实例,并通过该实例调用原型上的render方法3.将render返回的虚拟dom转为真实dom,税后呈现在页面中*/
</script>
</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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{constructor(props){super(props)this.state = {isHot:true}}render(){console.log(this)const {isHot} = this.statereturn <h2>今天天气很{isHot?'炎热':'凉爽'}——复杂组件(有状态)</h2>}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))/*第一个参要写闭合的组件*/</script>
</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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{//构造器调用几次?——1次constructor(props){super(props)this.state = {isHot:true}//注:call会直接执行,而bind是返回一个新的函数,需要手动执行,所以这里只能用bindthis.demo = this.demo.bind(this)}//render调用几次?——1+n次 1是初始化的 n是状态更新的次数render(){const {isHot} = this.state//注意:1.点击onClick不要写成onclick 2.调用不要加()如果加会初始化自己会调用return <h2 onClick={this.demo}>今天天气很{isHot?'炎热':'凉爽'}</h2>//为什么要改变this指向是因为οnclick=this.demo本质意义上并没有调用而是直接把这个方法复制过来,(浅拷贝)所以this为undefined}demo(){//demo放在哪里?——MyComponent的原型对象上,供实例使用//由于demo是作为onClick的回调,所以不是通过实例调用的,是直接调用//类中的方法默认开启了局部的严格模式,所以demo中的this为undefinedconst isHot = this.state.isHot//注意:状态(state)不可直接更改,下面这行就是直接更改//this.state.isHot = !isHot//这是错误的写法//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。this.setState({isHot:!isHot})}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))/*第一个参要写闭合的组件*//*bind:function demo(){console.log(this)}//demo.bind({a:1})//直接这么写不会执行,需要调用才会执行const x = demo.bind({a:1})x()*/</script>
</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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{constructor(props){super(props)// this.state = {isHot:true}// this.demo = this.demo.bind(this)}state = {isHot:true} //类中可以直接写赋值语句render(){const {isHot} = this.statereturn <h2 onClick={this.demo}>今天天气很{isHot?'炎热':'凉爽'}</h2>}//自定义方法——要用赋值语句的形式+箭头函数demo=()=>{const isHot = this.state.isHotthis.setState({isHot:!isHot})}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

理解:

  1. state是组件对象最重要的属性,值是对象(可以包含多个key-valuie的组合)
  2. 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)

强烈注意:

  1. 组件中render方法中的this为组件实例对象
  2. 组件自定义的方法中this为undefined,如何解决?
    1. 强制绑定this通过函数对象的bind()
    2. 箭头函数
  3. 状态数据,不能直接修改或更新

props

<!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>Document</title>
</head>
<body><div id="app"></div><div id="test"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script><!-- 引入prop-types 用于对组件标签属性进行限制 --><script src="https://unpkg.com/prop-types@15.6/prop-types.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{render(){//props是只读的const {name,age} = this.propsconsole.log(this)return (<ul><li>姓名:{name}</li>    <li>性别:{age+1}</li>    </ul>)}}MyComponent.propTypes={//name:ProtoTypes.string//这种写法在16.xxx写法可以//name:React.PropTypes这种写法在15.5xx版本之前可以,在16.xxx就被弃用了name:PropTypes.string.isRequired,//string必须是string+isRequired必填项age:PropTypes.number//function=>.func——限制函数}MyComponent.defaultProps={age:50}const p = {name:'lisa',age:18}//2.渲染组件到页面ReactDOM.render(<MyComponent name="tom" age="18"/>,document.getElementById('app'))ReactDOM.render(<MyComponent {...p}/>,document.getElementById('test'))//{...p}=>由于react+babel导致允许你在标签中这样写,不然拓展运算符是不可以展开对象的/*展开运算符:let arr1 = [1,2,3,4]let arr2 = [7,8,9,6]console.log(...arr1)//1.展开一个数组let arr3 = [...arr1,...arr2] console.log(arr3)//2.连接数组function sum(...numbers){//求和return numbers.reduce((preValue,currentValue)=>{return preValue+currentValue})}sum(1,5,6,7)//3.函数传参let person = {name:'tom',age:18} let person2 = {...person}//深拷贝console.log(...person)//报错,展开运算符不能展开对象*/
</script>
</html>

props简写

<!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>Document</title>
</head>
<body><div id="app"></div><div id="test"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script><!-- 引入prop-types 用于对组件标签属性进行限制 --><script src="https://unpkg.com/prop-types@15.6/prop-types.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{//对标签属性进行类型、必要性的限制static propTypes={name:React.PropTypes.string.isRequired,age:React.PropTypes.number}//指定默认标签属性值static defaultProps={age:50}render(){//props是只读的const {name,age} = this.propsconsole.log(this)return (<ul><li>姓名:{name}</li>    <li>性别:{age+1}</li>    </ul>)}}const p = {name:'lisa',age:18}//2.渲染组件到页面ReactDOM.render(<MyComponent name="tom" age="18"/>,document.getElementById('app'))ReactDOM.render(<MyComponent {...p}/>,document.getElementById('test'))//{...p}=>由于react+babel导致允许你在标签中这样写,不然拓展运算符是不可以展开对象的</script>
</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>Document</title>
</head>
<body><div id="app"></div><div id="test"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script><!-- 引入prop-types 用于对组件标签属性进行限制 --><script src="https://unpkg.com/prop-types@15.6/prop-types.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{//构造器_类中的构造器基本不会使用constructor(props){//构造器是否接受props,是否传递给super,取决于:是否希望在构造器中通过this访问propssuper(props)console.log(props)}//对标签属性进行类型、必要性的限制static propTypes={name:React.PropTypes.string.isRequired,age:React.PropTypes.number}//指定默认标签属性值static defaultProps={age:50}render(){//props是只读的const {name,age} = this.propsconsole.log(this)return (<ul><li>姓名:{name}</li>    <li>性别:{age+1}</li>    </ul>)}}const p = {name:'lisa',age:18}//2.渲染组件到页面ReactDOM.render(<MyComponent name="tom" age="18"/>,document.getElementById('app'))ReactDOM.render(<MyComponent {...p}/>,document.getElementById('test'))//{...p}=>由于react+babel导致允许你在标签中这样写,不然拓展运算符是不可以展开对象的</script>
</html>

函数式组件获取props

<!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>Document</title>
</head>
<body><div id="app"></div><div id="test"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script><!-- 引入prop-types 用于对组件标签属性进行限制 --><script src="https://unpkg.com/prop-types@15.6/prop-types.min.js"></script>
</body>
<script type="text/babel">function MyComponent(props) {console.log(props)return (<ul><li>姓名:{name}</li>    <li>性别:{age}</li>    </ul>)}//对标签属性进行类型、必要性的限制MyComponent.propTypes={name:React.PropTypes.string.isRequired,age:React.PropTypes.number}//指定默认标签属性值MyComponent.defaultProps={age:50}//2.渲染组件到页面ReactDOM.render(<MyComponent name="tom" age="18"/>,document.getElementById('app'))
</script>
</html>

refs

勿过渡使用ref
什么时候不使用ref而使用event?
发生事件的元素正好是你要操作的元素的时候

字符串形式的ref(过时的api——)
不建议使用(string的ref存在一些效率问题——效率不高)

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{render(){return (<ul><li ref="name" onClick={this.demo}>姓名:lily</li>    <li>性别:女</li>    </ul>)}demo = ()=>{console.log(this.refs.name)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

回调形式的ref

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{render(){return (<ul>{/*内联函数写法(一般工作中这种写法比较多):<li ref={currentNode=>this.input1 = currentNode} onClick={this.demo}>姓名:lily</li>*/}    <li ref={this.getrefs}>性别:女</li>    </ul>)/*回调ref中调用执行次数的问题:如图内联写法和定义成class绑定函数的区别:(无关紧要——不会有多大的影响)内联函数更新的时候会触发两次 一次为null一次为当前节点*//*ref={currentNode=>this.input1 = currentNode} <=> ref={(a)=>{this.input1 = a}} 意义:把ref当前所处的节点挂载了实例自身上并且取了一个名字教input1*/}getrefs=(c)=>{this.input1 = c}demo = ()=>{const {input1} = thisconsole.log(input1)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

在这里插入图片描述
createRef

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{//React.createRef调用后可以返回一个容器,改容器可以存储被ref所标识的节点//该容器是“专人专用”的//每用一个就要写一个下面的myRef = React.createRef()myRef2 = React.createRef()render(){return (<ul><li ref={this.myRef} onClick={this.demo}>姓名:lily</li>   <li ref={this.myRef2} onClick={this.demo2}>性别:女</li>     </ul>)}demo = ()=>{console.log(this.myRef.current)}demo2 = ()=>{console.log(this.myRef2.current)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

事件处理

  1. 通过onXxx属性指定事件处理函数(注意大小写)
    1. React使用的是自定义(合成)事件,而不是使用的原生DOM事件——为了更好的兼容性
    2. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)——为了高效
  2. 通过event.target得到发生事件的DOM元素对象.——不要过渡的使用ref
<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{dot=(event)=>{console.log(event.target)}render(){return (<ul><li onClick={this.dot}>点我一下</li></ul>)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

包含表单的组件分类

非受控组件

所有输入类的DOM(checkbox、radio、input...)现用现取

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{handleSubmit=(event)=>{event.preventDefault();//阻止默认事件const {username,password} = thisalert(`用户名${username.value}密码${password.value}`)}render(){return (<form onSubmit={this.handleSubmit}>用户名:<input ref={c=>this.username=c} type="text" name="username"/>密码:<input ref={c=>this.password=c} type="password" name="password"/><button>登录</button></form>)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

受控组件

页面中所有输入类的DOM,随着输入,就会把你输入的内容维护到状态里面去,等需要用的时候直接从状态里去拿

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{// 初始化状态state={username:'',password:''}// 表单提交问题handleSubmit=(event)=>{event.preventDefault();//阻止默认事件const {username,password} = this.stateconsole.log(username,password)}// 保存用户名到状态中getUsername=(event)=>{this.setState({username:event.target.value})}// 保存密码到状态中getPassword=(event)=>{this.setState({password:event.target.value})}render(){return (<form onSubmit={this.handleSubmit}>用户名:<input onChange={this.getUsername} type="text" name="username"/>密码:<input onChange={this.getPassword}   type="password" name="password"/><button>登录</button></form>)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

建议使用受控组件,因为受控组件中未使用ref

高阶函数_函数的柯里化

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{// 初始化状态state={username:'',password:''}// 获取表单数据到状态中handleSubmit=(event)=>{event.preventDefault();//阻止默认事件const {username,password} = this.stateconsole.log(username,password)}getFormData=(dataType)=>{console.log(dataType)return (event)=>{//这种写法是有返回值的(返回的函数)————onChange调用的函数获取的就是eventthis.setState({[dataType]:event.target.value})}}render(){return (<form onSubmit={this.handleSubmit}>{/*onChange={this.getFormData('username')}————这种写法的意思是把这个函数getFormData的返回值作为onchange回调——(因为他的返回值是undefined所以就没有效果)getFormData=(event)=>{//这种写法的返回值为undefinedthis.setState({username:event.target.value})}*/}{/*<input onChange={this.getFormData('username')} type="text" name="username"/>*/}用户名:<input onChange={this.getFormData('username')} type="text" name="username"/>密码:<input onChange={this.getFormData('password')}   type="password" name="password"/><button>登录</button></form>)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))/*对象相关的知识:let a ='name'let obj = {}obj[a]='tom'console.log(obj)*/
</script>
</html>

高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数
1. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数
2. 若A函数,调用的参数是一个函数,那么A就可以称之为高阶函数
常见的高阶函数有:promise setTimeout arr.map()
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式
(让注释代码折叠:#region/**/#endregion)

不用柯里化的写法

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class MyComponent extends React.Component{// 初始化状态state={username:'',password:''}// 获取表单数据到状态中handleSubmit=(event)=>{event.preventDefault();//阻止默认事件const {username,password} = this.state}getFormData=(dataType,value)=>{this.setState({[dataType]:event.target.value})}render(){return (<form onSubmit={this.handleSubmit}>用户名:<input onChange={(event)=>{this.getFormData('username',event)}} type="text" name="username"/>密码:<input onChange={(event)=>{this.getFormData('password',event)}}   type="password" name="password"/><button>登录</button></form>)}}//2.渲染组件到页面ReactDOM.render(<MyComponent/>,document.getElementById('app'))
</script>
</html>

生命周期

引出生命周期

componentDidMount——组件挂载完毕
componentWillUnmount——组件将要卸载
render——初始化渲染‘状态更新之后’

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">//1.创建类式组件class Life extends React.Component{/*状态*/state = {opacity:1}/*方法*/death = ()=>{// 卸载组件ReactDOM.unmountComponentAtNode(document.getElementById('app'))}/*生命周期*///组件挂载完毕componentDidMount(){//只执行一次this.timer=setInterval(() => {//获取原状态let {opacity} = this.state//减小0.1opacity-=0.1if(opacity<=0) opacity=1//设置新的透明度this.setState({opacity})}, 200);}//组件将要卸载componentWillUnmount(){//清除定时器clearInterval(this.timer)}/*初始化渲染*/render(){return (<div><h2 style={{opacity:this.state.opacity}} >学不会react怎么办?</h2>  <button onClick={this.death}>不活了</button>  </div>)}}//2.渲染组件到页面ReactDOM.render(<Life/>,document.getElementById('app'))
</script>
</html>

理解

  1. 组件从创建到死亡会经历一些特定的阶段
  2. react组件中包含一系列钩子函数(生命周期回调函数),会在特定的时刻调用
  3. 我们在定义组件时,会在特定的生命周期回调函数,中做特定的工作

生命周期(旧)

在这里插入图片描述

shouldComponentUpdate默认是true 即使不调用

挂载时

<!DOCTYPE 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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">class Count extends React.Component{// 构造器constructor(props){console.log('count-constructor')super(props)this.state={count:0}}add=()=>{const {count} = this.statethis.setState({count: count+1})}death=()=>{ReactDOM.unmountComponentAtNode(document.getElementById('app'))}// 组件将要挂载的钩子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><div>{count}</div><div onClick={this.add}>点击+1</div> <div onClick={this.death}>点击卸载组件</div>   </div>)}}//2.渲染组件到页面ReactDOM.render(<Count/>,document.getElementById('app'))
</script>
</html>

父组件render
路线一

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">class Count extends React.Component{// 构造器constructor(props){console.log('count-constructor')super(props)this.state={count:0}}add=()=>{const {count} = this.statethis.setState({count: count+1})}death=()=>{ReactDOM.unmountComponentAtNode(document.getElementById('app'))}// 组件将要卸载的钩子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><div>{count}</div><div onClick={this.add}>点击+1</div> <div onClick={this.death}>点击卸载组件</div>   </div>)}}//2.渲染组件到页面ReactDOM.render(<Count/>,document.getElementById('app'))
</script>
</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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">class Count extends React.Component{// 构造器constructor(props){console.log('count-constructor')super(props)this.state={count:0}}add=()=>{const {count} = this.statethis.setState({count: count+1})}death=()=>{ReactDOM.unmountComponentAtNode(document.getElementById('app'))}//强制更新force=()=>{this.forceUpdate()}// 组件将要卸载的钩子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><div>{count}</div><div onClick={this.add}>点击+1</div> <div onClick={this.death}>点击卸载组件</div>   <div onClick={this.force}>不更改状态,强制更新</div></div>)}}//2.渲染组件到页面ReactDOM.render(<Count/>,document.getElementById('app'))
</script>
</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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<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}/></div>)}}class B extends React.Component{//将要props(需要新的,意思就是刚接收的不算,只有新的在算)componentWillReceiveProps(){console.log('b')}//控制组件更新的阀门(必须要return布尔值)shouldComponentUpdate(){console.log('b-shouldComponentUpdate')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/>,document.getElementById('app'))
</script>
</html>

总结

   /*1.初始化阶段:由ReactDOM。render()触发————初次渲染1.constructor()2.componentWillMount()3.render()4.componentDidMount()2.更新阶段:由组件内部this.setState()或父组件重新render触发1.shouldComponentUpdate()2.componentWillUpdate()3.render()4.componentDidUpdate()3.卸载组件:由ReactDOM.unmountComponentAtNode()触发1.componentWillUnmount()*/

新的生命周期

对比旧的生命周期

 /*在新版本里,旧的生命周期前面需要加 UNSEFE_  来解决警告 只有一下三个需要加1.componentWillMount2.componentWillReceiveProps3.componentWillUpdate*/

在这里插入图片描述

新的生命周期

/*挂载时*/
<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">class Count extends React.Component{// 构造器constructor(props){console.log('count-constructor')super(props)this.state={count:0}}add=()=>{const {count} = this.statethis.setState({count: count+1})}death=()=>{ReactDOM.unmountComponentAtNode(document.getElementById('app'))}force=()=>{this.forceUpdate()}// 组件将要卸载的钩子componentWillUnmount(){console.log('count-componentWillUnmount')}//控制组件更新的阀门shouldComponentUpdate(){console.log('count-shouldComponentUpdate')return false}// 组件更新完毕的钩子componentDidUpdate(){console.log('count-componentDidUpdate')}//派生组件会导致代码沉余,并使用组件难以维护(了解即可)static getDerivedStateFromProps(props,state){//基本上以后用不到//props是传的值console.log('getDerivedStateFromProps',props,state)//必须有返回值:第一种返回值是个状态对象,第二种返回值是nullreturn props//一旦返回状态对象,那么状态的更新就不执行了__若state值在任何时候都取决于props(这是其中一种解决办法,还有一种解决办法就是在构造器中给状态对象赋值props即可),那么可以使用//return null  不影响功能}render(){console.log('count-render')const {count} = this.statereturn(<div><div>{count}</div><div onClick={this.add}>点击+1</div> <div onClick={this.death}>点击卸载组件</div>   <div onClick={this.force}>不更改状态,强制更新</div></div>)}}//2.渲染组件到页面ReactDOM.render(<Count count="199"/>,document.getElementById('app'))
</script>
</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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">class Count extends React.Component{// 构造器constructor(props){console.log('count-constructor')super(props)this.state={count:0}}add=()=>{const {count} = this.statethis.setState({count: count+1})}death=()=>{ReactDOM.unmountComponentAtNode(document.getElementById('app'))}force=()=>{this.forceUpdate()}// 组件将要卸载的钩子componentWillUnmount(){console.log('count-componentWillUnmount')}//控制组件更新的阀门shouldComponentUpdate(){console.log('count-shouldComponentUpdate')return false}// 组件更新完毕的钩子componentDidUpdate(preProps,preState,snapshotValue){console.log('count-componentDidUpdate',preProps,preState,snapshotValue)}//派生组件会导致代码沉余,并使用组件难以维护(了解即可)static getDerivedStateFromProps(props,state){//基本上以后用不到//props是传的值console.log('getDerivedStateFromProps',props,state)//必须有返回值:第一种返回值是个状态对象,第二种返回值是nullreturn null//一旦返回状态对象,那么状态的更新就不执行了__若state值在任何时候都取决于props(这是其中一种解决办法,还有一种解决办法就是在构造器中给状态对象赋值props即可),那么可以使用//return null  不影响功能}//在更新之前获取快照getSnapshotBeforeUpdate(){console.log('getSnapshotBeforeUpdate')//有返回值:字符串或者nullreturn 'null'}render(){console.log('count-render')const {count} = this.statereturn(<div><div>{count}</div><div onClick={this.add}>点击+1</div> <div onClick={this.death}>点击卸载组件</div>   <div onClick={this.force}>不更改状态,强制更新</div></div>)}}//2.渲染组件到页面ReactDOM.render(<Count count={199}/>,document.getElementById('app'))
</script>
</html>
/*getSnapshotBeforeUpdate_-___案例*/
<!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>Document</title><style>.list{width: 200px;height: 210px;max-height: 210px;overflow: auto;background: bisque;}.news{height: 30px;}</style>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">class Count extends React.Component{state = {newsArr:[]}componentDidMount(){setInterval(() => {const {newsArr} = this.state//模拟一条新闻const 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(<Count count={199}/>,document.getElementById('app'))
</script>
</html>

总结

/*1.初始化阶段:由ReactDOM.render()触发——————初次渲染1.constructor()2.getDeriverStateFromProps3.render()4.componentDidMount2.更新阶段:由组件内部this.setState()或父组件重新render触发1.getDerivedStateFromProps2.shouldComponentUpdate()3.render()4.getSnapshotBeforeUpdate5.componentDidUpdate3.卸载组件:由ReactDom.unmountComponentAtNode()触发1.componentWillUnmount()*/

DOM的diffing算法

<!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>Document</title>
</head>
<body><div id="app"></div><!-- 注意:三者引入顺序 --><!-- react核心库 --><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script><!-- 引入react-dom用于支持react操作DOM --><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><!-- 引入babel 用于将jsx转换为js --><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</body>
<script type="text/babel">/*问题:1. react/vue中的key有什么作用?(key的内部原理是什么?)2.为什么遍历列表时,key最好不要用index?答案:1.虚拟dom中key的作用:1)简单的说:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用2)详细的说:当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟dom】,随后react进行【新的虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:a.旧虚拟DOM中找了与新虚拟DOM相同的key1)若虚拟DOM中内容没变,直接使用之前的真实DOM2)若虚拟DOM中内容变了,则生成新的真实DOM,随后替换页面中之前的真实DOMb.旧虚拟DOM中未找到与新虚拟DOM相同key根据数据创建新的真实DOM,随后渲染到页面2.用index作为key可能会引发的问题1)若对数据进行:逆序添加‘逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新===》界面效果没问题,但效率低2)如果结构中还包含输入类的DOM:会产生错误DOM更新==》界面有问题3)注意:如果不存在对数据的逆序添加’逆序删除等破坏顺序操作仅用于渲染列表用于展示,使用index作为key是没有问题的3.开发中如何选择key?1.最好使用每条数据的唯一标识作为key,比如id...2.如果确定只是简单的展示数据、用index也是可以的-*/
//    class Time extends React.Component{
//     state = {date:new Date()}
//     componentDidMount(){
//         setInterval(()=>{
//             this.setState({
//                 date:new Date()
//             })
//         },1000)
//     }
//     render(){
//         return (
//             <div>
//                 <input type="text"/>    
//                 <span>{this.state.date.toTimeString()}</span>
//             </div>
//         )
//     }
//    }//2.渲染组件到页面ReactDOM.render(<Time />,document.getElementById('app'))
</script>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_228886.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于jsp+mysql+ssm协同办公系统-计算机毕业设计

项目介绍 本公司文档协同办公管理系统采用SSM&#xff08;SpringSpringMVCMyBatis&#xff09;框架开发,主要包括系统用户管理模块、用户信息模块、文件信息管理、个人事务管理、资料信息管理、登录模块、和退出模块等多个模块. 本系统主要包含了等系统用户管理、用户信息管理…

数据结构学习笔记(Ⅶ):查找

目录 1 查找 1.1 定义 1.2 查找操作 1.3 算法评价指标 2 查找算法 2.1 顺序查找 1.算法思想 2.实现 3.查找效率 4.算法优化 2.2 折半查找 1.算法思想 2.算法实现 3.查找判定树 4.折半查找效率 2.3 分块查找 1.算法思想 2.查找效率分析 3 B树 3.1 B树概念 3…

独立站SaaS系统站群模式怎么玩

做独立站的人都知道“站群”这个游戏&#xff0c;意思是通过建站工具一次性建好几百个或者几千个独立站。各个独立站卖的品类比较垂直&#xff0c;不会有太多SKU。销量好的站会留着精细化运营&#xff0c;没流量的就放弃。 使用脸书或谷歌和其他广告渠道来测试产品。每个产品…

手把手教你写Linux线程池

手把手教你写Linux线程池 如果需要线程池源码&#xff0c;关注Linux兵工厂&#xff0c;并由大量Linux资料赠送。 线程池 顾名思义&#xff0c;存储线程的池子。线程池是线程的一种使用模式。在平常业务开发中常规的逻辑是遇到任务然后创建线程去执行。但是线程的频繁创建就类…

Java Tomcat内存马——Listener内存马

目录 &#xff08;一&#xff09;前置知识 0x01 什么是Listener 0x02 Listener的简单案例 0x03 Listener流程分析 &#xff08;二&#xff09;注入分析 (三&#xff09;实现内存马 得到完整的内存马 (四&#xff09;漏洞复现 其他的payload: 总结 &#xff08;一&#…

Java+JSP+MySQL基于SSM的雷锋车队管理系统的设计与实现-计算机毕业设计

项目介绍 随着我国国民经济的发展和人文素质的不断提高&#xff0c;越来越多的爱心人士出现在了社会的各种角落之中&#xff0c;其中的哥和爱心人士&#xff0c;组织了一种基于交通和车辆之间的互助的民间组织&#xff0c;这种组织叫做雷锋爱心车队&#xff0c;而且雷锋爱心车…

什么牌子蓝牙耳机通话质量好?通话质量好的蓝牙耳机推荐

蓝牙耳机作为手机的最佳伴侣&#xff0c;已经成为老百姓日常生活必备。每次有大品牌发布新款蓝牙耳机&#xff0c;几乎都能够得到很好的反响&#xff0c;蓝牙耳机不仅在音质上有了很大的提升&#xff0c;并且在其他功能也在不断的提升&#xff0c;使用蓝牙耳机通话避免不了电话…

商务部研究院信用所、启信宝联合发布《中国商务信用发展指数报告(2022)》

近期&#xff0c;商务部国际贸易经济合作研究院信用研究所与合合信息全资子公司上海生腾数据科技有限公司&#xff08;简称“生腾数据”&#xff09;联合发布了《中国商务信用发展指数报告&#xff08;2022&#xff09;》&#xff08;简称《报告》&#xff09;。为准确反映中国…

glxy_阿里云存储

阿里云OSS储存 讲师的添加实现&#xff1a;oss服务 访问并登陆阿里云&#xff0c;&#xff0c;实名认证 产品分类---->对象储存OSS 开通OSS 进入管理控制台 使用OSS前先创建bucket java 代码实现 准备工作&#xff1a;创建操作阿里云oss许可证&#xff08;阿里云颁发…

得一微冲刺科创板上市:拟募资约12亿元,2021年营收同比增长260%

撰稿|汤汤 来源|贝多财经 近日&#xff0c;得一微电子股份有限公司&#xff08;下称“得一微”&#xff09;在上海证券交易所科创板递交招股书&#xff08;申报稿&#xff09;。本次冲刺科创板上市&#xff0c;得一微拟公开发行不超过2354万股股份&#xff0c;计划募资12.24亿…

zookeeper学习(一)zk特性与节点数据类型详解(2022)

Zookeeper是一个开源的分布式协调框架&#xff0c;主要用来解决分布式集群中应用系统的一致性问题。从设计模式角度来理解其实zk是一个基于观察者模式设计的分布式服务管理框架。 CAP理论&#xff1a; cap理论指出对于一个分布式计算系统来说&#xff0c;不可能同时满足以下三…

golang知识点整理

目录 1、goroutine GMP模型 2、goroutine阻塞的处理 3、goroutine内存泄漏 4、map原理、扩容 5、go内存管理 6、go的gc 1、goroutine GMP模型 1. G代表一个goroutine对象&#xff0c;每次go调用的时候&#xff0c;都会创建一个G对象 2. M代表一个线程&#xff0c;每次创建…

SpringCloud:Gateway之限流、熔断

目录 一、服务雪崩简介及压测实践演示 ​编辑 二、sentinel简单模式之流控QPS案例 什么是Sentinel ​ 安装Sentinel控制台 三、sentinel流控简单模式之并发线程数案例 四、sentinel流控之关联模式&链路模式 关联模式 链路模式 五、sentinel降级之平均响应时间&…

最新 | VDA-ISA5.0.4最新版本发布,汽车企业如何增强信息安全?

汽车行业拥有广泛而复杂的供应链&#xff0c;包括汽车整车制造商、不同层级的零部件厂商、供应商、服务商等众多企业。在这个链条上&#xff0c;其中任何一家企业的网络安全问题不论是数据泄密还是内外部攻击都有可能对整个供应链造成巨大影响。 比如2021年6月&#xff0c;某德…

能力提高篇--协调能力【对接】

作为一名安防技术支持工程师&#xff0c;正常情况下我们的日常主要为解决问题&#xff0c;然而对于重大项目或者复杂项目&#xff0c;更多的情况下我们的职责为收集客户需求&#xff0c;拉通研发侧评估&#xff0c;确认需求&#xff0c;确认程序交付时间&#xff0c;测试和最终…

【python与数据分析】实验十三 北京市空气质量

目录 一、实验内容 二、完成情况 三、数据分析 1.问题描述 2.编程思路 3.程序代码 4.程序运行结果 &#xff08;1&#xff09;2014年-2019年AQI时间序列折线图 &#xff08;2&#xff09;各年AQI折线图、AQI直方图、PM2.5与AQI散点图、空气质量整体情况的饼图 ​&am…

10-18-hive-元数据及其他方式与hive交互

10-hive-元数据及其他方式访问hive&#xff1a; 使用元数据服务的方式访问 Hive (类似将hive提供了一个服务端) 1&#xff09;在hive-site.xml 文件中添加如下配置信息 <!-- 指定存储元数据要连接的地址 --> <property> <name>hive.metastore.uris</nam…

[附源码]计算机毕业设计SpringBoot网上鲜花购物系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Day16-购物车页面-商品列表修改购物车商品的勾选状态

提纲挈领&#xff1a; 我的操作&#xff1a; 1》当用户点击 radio 组件&#xff0c;希望修改当前商品的勾选状态&#xff0c;此时用户可以为 my-goods 组件绑定 radio-change 事件&#xff0c;从而获取当前商品的 goods_id 和 goods_state&#xff1a; 定义 radioChangeHandle…

leetcode-每日一题-1779-找到最近的有相同 X 或 Y 坐标的点(简单,数学思想)

今天这道每日一题很简单&#xff0c;没啥可说的&#xff0c;细心点即可 1779. 找到最近的有相同 X 或 Y 坐标的点 难度简单73收藏分享切换为英文接收动态反馈 给你两个整数 x 和 y &#xff0c;表示你在一个笛卡尔坐标系下的 (x, y) 处。同时&#xff0c;在同一个坐标系下给你一…