【react-笔记】

简介

  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.创建虚拟DOM
    const 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.创建虚拟DOM
	const 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.创建虚拟DOM
    const 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 = name
            this.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.state
            return <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是返回一个新的函数,需要手动执行,所以这里只能用bind
            this.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为undefined
           const 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.state
            return <h2 onClick={this.demo}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        //自定义方法——要用赋值语句的形式+箭头函数
        demo=()=>{
           const isHot = this.state.isHot
           this.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.props
            console.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.props
            console.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访问props
            super(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.props
            console.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} = this
            console.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} = this
            alert(`用户名${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.state
            console.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.state
            console.log(username,password)
        }
        getFormData=(dataType)=>{
            console.log(dataType)
            return (event)=>{//这种写法是有返回值的(返回的函数)————onChange调用的函数获取的就是event
                this.setState({[dataType]:event.target.value})
            }
        }
        render(){
           return (
                <form onSubmit={this.handleSubmit}>
                    {/*
                    onChange={this.getFormData('username')}————这种写法的意思是把这个函数getFormData的返回值作为onchange回调——(因为他的返回值是undefined所以就没有效果)
                    getFormData=(event)=>{//这种写法的返回值为undefined
                        this.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.1
                opacity-=0.1
                if(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.state
            this.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.state
            return(
                <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.state
            this.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.state
            return(
                <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.state
            this.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.state
            return(
                <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.componentWillMount
        2.componentWillReceiveProps
        3.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.state
            this.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)//必须有返回值:第一种返回值是个状态对象,第二种返回值是null
            return props//一旦返回状态对象,那么状态的更新就不执行了__若state值在任何时候都取决于props(这是其中一种解决办法,还有一种解决办法就是在构造器中给状态对象赋值props即可),那么可以使用
            //return null  不影响功能
        }
        render(){
            console.log('count-render')
            const {count} = this.state
            return(
                <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.state
            this.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)//必须有返回值:第一种返回值是个状态对象,第二种返回值是null
            return null//一旦返回状态对象,那么状态的更新就不执行了__若state值在任何时候都取决于props(这是其中一种解决办法,还有一种解决办法就是在构造器中给状态对象赋值props即可),那么可以使用
            //return null  不影响功能
        }
        //在更新之前获取快照
        getSnapshotBeforeUpdate(){
            console.log('getSnapshotBeforeUpdate')//有返回值:字符串或者null
            return 'null'
        }
        render(){
            console.log('count-render')
            const {count} = this.state
            return(
                <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.getDeriverStateFromProps
                3.render()
                4.componentDidMount
        2.更新阶段:由组件内部this.setState()或父组件重新render触发
                1.getDerivedStateFromProps
                2.shouldComponentUpdate()
                3.render()
                4.getSnapshotBeforeUpdate
                5.componentDidUpdate
        3.卸载组件:由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相同的key
                        1)若虚拟DOM中内容没变,直接使用之前的真实DOM
                        2)若虚拟DOM中内容变了,则生成新的真实DOM,随后替换页面中之前的真实DOM
                    b.旧虚拟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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值