[尚硅谷React笔记]——第2章 React面向组件编程

news/2024/7/15 17:29:27 标签: 前端, javascript, react.js

 目录:

  1. 基本理解和使用:
    1. 使用React开发者工具调试
    2. 函数式组件
    3. 复习类的基本知识
    4. 类式组件
  2. 组件三大核心属性1: state
    1. 复习类中方法this指向: 
    2. 复习bind函数:
    3. 解决changeWeather中this指向问题:
    4. 一般写法:state.html
    5. 在精简写法之前,复习一下类的基本知识:
    6. 精简写法:
  3. 组件三大核心属性2: props
    1. props的基本使用.html
    2. 复习展开运算符.html
    3. 使用展开运算符,批量传递props
    4. 对props进行限制
    5. props的简写方式.html
    6. 类式组件中的构造器与props:
    7. 函数式组件使用props:
  4. 组件三大核心属性3: refs与事件处理
    1. 字符串形式的ref
    2. 回调形式的ref
    3. 回调ref中调用次数的问题
    4. createRef的使用
    5. 事件处理
  5. 收集表单数据
    1. 非受控组件
    2. 受控组件
  6. 高阶函数,函数柯里化
    1. 高阶函数,函数柯里化
    2. 对象相关的知识
    3. 演示函数的柯里化
  7. 组件的生命周期
    1. ​​​​​​​引出生命周期
    2. react生命周期(旧) 
    3. react生命周期(l日)_setState流程
    4. react生命周期(l日)_forceUpdate流程
    5. react生命周期(l日)_父组件render流程
    6. react新生命周期
    7. react生命周期(新)_getDerivedStateFromProps
    8. react生命周期(新)_getSnapshotBeforeUpdate
    9. react生命周期(新)_getSnapshotBeforeUpdate的使用场景
  8. 虚拟DOM与DOM Diffing算法
    1. 验证Diffing算法
    2. key的作用

1.基本理解和使用:

使用React开发者工具调试

函数式组件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
    function MyComponent() {
        console.log(this)//此处的this是undefined,因为babel编译后开启了严格模式
        return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
    }

    ReactDOM.render(<MyComponent></MyComponent>, document.getElementById('test'))

    // 执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
    //    1.React解析组件标签,找到了MyComponent组件。
    //    ⒉发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DON转为真实DOM,随后呈现在页面中。
</script>
</body>
</html>

运行结果:

复习类的基本知识:

总结:

  1. 类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时厅与。
  2. 如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。
  3. 类中所定义的方法,都是放在了类的原型对象上,供实例去使用

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    // 创建一个Person类
    class Person {
        //构造器方法
        constructor(name, age) {
            //构造器中的this是谁?—类的实例对象
            this.name = name
            this.age = age
            this.school = '尚硅谷'
        }

        //一般方法
        speak() {
            //speak方法放在了哪里?—类的原型对象上,供实例使用
            //通过Person实例调用speak时,speak中的this就是Person实例
            console.log(`我叫${this.name},我年龄是${this.age}`)
        }
    }

    //创建一个Student类,继承于Person类
    class Student extends Person {
        constructor(name, age, grade) {
            super(name, age);
            this.grade = grade
        }

        //重写从父类继承过来的方法
        speak() {
            console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`)
        }

        study() {
            //study方法放在了哪里?—类的原型对象上,供实例使用
            //通过student实例调用study时,study中的this就是Student实例
            console.log('我很努力的学习')
        }
    }

    const s1 = new Student('小张', 15, '高一')
    console.log(s1)
    s1.speak()
    s1.study()
</script>
</body>
</html>

类式组件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
    //1.创建类式组件
    class MyComponent extends React.Component {
        render() {
            //render是放在哪里的?-—- MyComponent的原型对象上,供实例使用。
            //render中的this是谁?— MyComponent的实例对象。MyComponent组件实例对象
            return <h2>我是类定义的组件(适用于【复杂组件】的定义)</h2>
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<MyComponent/>, document.getElementById('test'))
    /**
     * 执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
     * 1.React解析组件标签,找到了MyComponent组件。
     * 2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
     * 3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
     * */
</script>
</body>
</html>

运行结果:

2.组件三大核心属性1: state

简介:

在React中,state是一个非常重要的属性,主要用于标识组件的状态,以及更新UI,使页面动态变化。

对于state的定义和使用,主要有以下特点:

  1. state的值是json对象类型,可以维护多个key-value的组合。
  2. 在类组件中,state是组件的一个默认属性,用于存储和跟踪组件的状态。当state变化时,组件将被重新渲染。这意味着React将根据最新的state值重新计算渲染输出,并对DOM进行更新。
  3. 在函数组件中,由于没有对象属性(babel默认开启了局部严格模式,函数内部this指向undefined),所以没有state属性。因此,函数组件只负责展示静态页面,而不进行动态更新。
  4. state的值是可变的,但props的值是只读的。props属性值可以进行类型、必要性限制,也可以设置属性默认值,但组件自身不能修改props属性值。

总的来说,React的state主要用于存储和更新组件的状态,从而可以动态地控制组件的渲染和显示内容。

复习原生事件绑定:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button onclick="demo()">按钮3</button>

<script type="text/javascript">
    const btn1 = document.getElementById('btn1')
    btn1.addEventListener('click', () => {
        alert('按钮1被点击了')
    })

    const btn2 = document.getElementById('btn2')
    btn2.onclick = () => {
        alert('按钮2被点击了')
    }

    function demo() {
        alert('按钮3被点击了')
    }


</script>
</body>
</html>

复习类中方法this指向: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    class Person {
        constructor(name, age) {
            this.name = name
            this.age = age
        }

        study() {
            //study方法放在了哪里?—类的原型对象上,供实例使用
            //通过Person实例调用study时,study中的this就是Person实例
            console.log(this)
        }
    }

    const p1 = new Person('tom', 18)
    p1.study()
    const x = p1.study
    x()


    //为了证明js自动在类中的方法上加了严格模式,this不指向window
    function demo() {
        console.log(this)
    }

    demo()

    function demo1() {
        'use strict'
        console.log(this)
    }

    demo1()


</script>
</body>
</html>

复习bind函数:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    function demo() {
        console.log(this)
    }

    demo()

    const x = demo.bind({a: 1, b: 2})
    x()
</script>
</body>
</html>

效果(需求: 定义一个展示天气信息的组件

  1. 默认展示天气炎热 凉爽
  2. 点击文字切换天气

 解决changeWeather中this指向问题:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
    //1.创建组件
    class Weather extends React.Component {
        constructor(props) {
            super(props);
            //初始化状态
            this.state = {isHot: true}
            //解决changeweather中this指向问题
            this.changeWeather = this.changeWeather.bind(this)
        }

        render() {
            const {isHot} = this.state
            return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}</h1>
        }

        changeWeather() {
            //changeweather放在哪里?—— weather的原型对象上,供实例使用
            //由于changeweather是作为onClick的回调,所以不是通过实例调用的,是直接调用
            //类中的方法默认开启了局部的严格模式,所以changeweather中的this为undefined
            console.log(this)
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>

 一般写法:state.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
    //1.创建组件
    class Weather extends React.Component {
        //构造器调用几次?  --  1次
        constructor(props) {
            console.log('constructor')
            super(props);
            //初始化状态
            this.state = {isHot: true, wind: '微风'}
            //解决changeweather中this指向问题
            this.changeWeather = this.changeWeather.bind(this)
        }

        //render调用几次?  --  1+n次 1是初始化的那次 n是状态更新的次数
        render() {
            console.log('render')
            const {isHot, wind} = this.state
            return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
        }

        //changeWeather调用几次?  --  点几次调几次
        changeWeather() {
            //changeweather放在哪里?—— weather的原型对象上,供实例使用
            //由于changeweather是作为onClick的回调,所以不是通过实例调用的,是直接调用
            //类中的方法默认开启了局部的严格模式,所以changeweather中的this为undefined
            // console.log(this)

            console.log('changeWeather')

            const isHot = this.state.isHot

            //严重注意:状态(state)不可直接更改,下面这行就是直接更改!! !
            // this.state.isHot = !isHot
            // console.log(this.state.isHot)

            // /严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
            this.setState({isHot: !isHot})
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>

在精简写法之前,复习一下类的基本知识:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    // 创建一个Person类
    class Person {
        //构造器方法
        constructor(name, age) {
            //构造器中的this是谁?—类的实例对象
            this.name = name
            this.age = age
            this.school = '尚硅谷'
        }

        //一般方法
        speak() {
            //speak方法放在了哪里?—类的原型对象上,供实例使用
            //通过Person实例调用speak时,speak中的this就是Person实例
            console.log(`我叫${this.name},我年龄是${this.age}`)
        }
    }

    //创建一个Student类,继承于Person类
    class Student extends Person {
        constructor(name, age, grade) {
            super(name, age);
            this.grade = grade
        }

        //重写从父类继承过来的方法
        speak() {
            console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`)
        }

        study() {
            //study方法放在了哪里?—类的原型对象上,供实例使用
            //通过student实例调用study时,study中的this就是Student实例
            console.log('我很努力的学习')
        }
    }

    //
    // const s1 = new Student('小张', 15, '高一')
    // console.log(s1)
    // s1.speak()
    // s1.study()

    class Car {
        constructor(name, price) {
            this.name = name
            this.price = price
        }

        a = 1
    }

    const c1 = new Car('奔驰c63', 199)
    const c2 = new Car('宝马', 299)
    console.log(c1)
    console.log(c2)
</script>
</body>
</html>

精简写法: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
    //1.创建组件
    class Weather extends React.Component {
        state = {isHot: true, wind: '微风'}

        render() {
            const {isHot, wind} = this.state
            return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
        }

        changeWeather = () => {
            const isHot = this.state.isHot
            this.setState({isHot: !isHot})
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>

理解

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

强烈注意

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

3.组件三大核心属性2: props

简介:

React中的props是一种类似于JavaScript函数的组件概念,它允许组件接收任意的输入参数,并返回用于描述页面展示内容的React元素。

具体来说,props的主要作用和用途包括以下几个方面:

  1. 传递数据:props可以用于向子组件传递数据,这些数据可能是父组件的状态或者是其他兄弟组件的状态。通过props,子组件可以获得父组件或其他组件传递过来的数据,从而更新自己的状态。
  2. 外部控制:通过props,父组件可以对子组件进行控制,例如设置初始状态或者传递回调函数。这种控制方式使得React的组件之间具有更好的互动性和协作性。
  3. 自定义行为:通过props,我们可以向组件传递一些自定义的属性,从而改变组件的行为或者样式。例如,我们可以向按钮组件传递一个“disabled”属性,使得按钮变得不可点击。
  4. 属性约束:与state不同,props是只读的,也就是说子组件不能修改父组件传递过来的props数据。这使得React的组件之间具有更好的可维护性和可预测性。

总的来说,React的props是一种强大的工具,它可以使得组件之间的数据传递更加灵活和高效,同时也可以使得组件的行为更加自定义和可控。

props的基本使用.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
    //创建组件
    class Person extends React.Component {
        render() {
            console.log(this)
            const {name, age, sex} = this.props
            return (
                // <ul>
                //     <li>姓名:{this.props.name}</li>
                //     <li>性别:{this.props.sex}</li>
                //     <li>年龄:{this.props.age}</li>
                // </ul>
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age}</li>
                </ul>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Person name="jerry" age="19" sex="男"></Person>, document.getElementById('test1'))
    ReactDOM.render(<Person name="kitty" age="20" sex="女"></Person>, document.getElementById('test2'))
    ReactDOM.render(<Person name="wang" age="19" sex="男"></Person>, document.getElementById('test3'))
</script>
</body>
</html>

复习展开运算符.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    let arr1 = [1, 3, 5, 7, 9]
    let arr2 = [2, 4, 6, 8, 10]
    console.log(...arr1)
    let arr3 = [...arr1, ...arr2]
    console.log(arr3)

    // function sum(a, b) {
    //     return a + b
    // }
    //
    // console.log(sum(1, 2))

    // function sum(...numbers) {
    //     console.log('@', numbers)
    // }
    //
    // console.log(sum(1, 2, 3, 4))

    function sum(...numbers) {
        return numbers.reduce((preValue, currentValue) => {
            return preValue + currentValue
        })
    }

    console.log(sum(1, 2, 3, 4))

    //构造字面量对象时使用展开语法
    let person = {name: 'tom', age: 18}
    let person2 = {...person}
    // console.log(...person) //报错,展开运算符不能展开对象
    console.log({...person})  //不报错,多加了一个{}

    person.name = 'jerry'
    console.log(person2.name)
    console.log(person)

    //合并
    let person3 = {...person, name: 'jack', address: '地球'}
    console.log(person3)
</script>
</body>
</html>

使用展开运算符,批量传递props

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
    //创建组件
    class Person extends React.Component {
        render() {
            console.log(this)
            const {name, age, sex} = this.props
            return (
                // <ul>
                //     <li>姓名:{this.props.name}</li>
                //     <li>性别:{this.props.sex}</li>
                //     <li>年龄:{this.props.age}</li>
                // </ul>
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age}</li>
                </ul>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Person name="jerry" age="19" sex="男"></Person>, document.getElementById('test1'))
    ReactDOM.render(<Person name="kitty" age="20" sex="女"></Person>, document.getElementById('test2'))

    const p = {name: '老刘', age: 18, sex: '女'}
    console.log(...p, '@');
    console.log({...p}, '@');
    // ReactDOM.render(<Person name="wang" age="19" sex="男"></Person>, document.getElementById('test3'))
    ReactDOM.render(<Person {...p}></Person>, document.getElementById('test3'))
</script>
</body>
</html>

对props进行限制

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Person extends React.Component {
        render() {
            console.log(this)
            const {name, age, sex} = this.props
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age + 1}</li>
                </ul>
            )
        }
    }

    //对标签属性进行类型、必要性的限制
    Person.propTypes = {
        name: PropTypes.string.isRequired,
        sex: PropTypes.string,
        age: PropTypes.number,
        speak: PropTypes.func
    }
    //指定默认标签属性值
    Person.defaultProps = {
        sex: '男',
        age: 18
    }

    //2.渲染组件到页面
    ReactDOM.render(<Person name="jerry" age={19} speak={speak}></Person>, document.getElementById('test1'))
    ReactDOM.render(<Person name="kitty" age={18} sex="女"></Person>, document.getElementById('test2'))

    const p = {name: '老刘', age: 18, sex: '女'}

    ReactDOM.render(<Person {...p}></Person>, document.getElementById('test3'))

    function speak() {
        console.log('我说话了')
    }
</script>
</body>
</html>

props的简写方式.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Person extends React.Component {
        //对标签属性进行类型,必要性的限制
        static propTypes = {
            name: PropTypes.string.isRequired,
            sex: PropTypes.string,
            age: PropTypes.number,
            speak: PropTypes.func
        }

        //指定默认标签属性值
        static defaultProps = {
            sex: '男',
            age: 18
        }

        render() {
            console.log(this)
            const {name, age, sex} = this.props
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age + 1}</li>
                </ul>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Person name="jerry" age={19} speak={speak}></Person>, document.getElementById('test1'))
    ReactDOM.render(<Person name="kitty" age={18} sex="女"></Person>, document.getElementById('test2'))

    const p = {name: '老刘', age: 18, sex: '女'}

    ReactDOM.render(<Person {...p}></Person>, document.getElementById('test3'))

    function speak() {
        console.log('我说话了')
    }
</script>
</body>
</html>

类式组件中的构造器与props:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Person extends React.Component {
        //构造器是否接受props,是否传递给super,取决于:是否希望在构造器中通过this访间props
        constructor(props) {
            console.log(props)
            super(props)
            console.log('constructor', this.props)
        }

        //对标签属性进行类型,必要性的限制
        static propTypes = {
            name: PropTypes.string.isRequired,
            sex: PropTypes.string,
            age: PropTypes.number,
            speak: PropTypes.func
        }

        //指定默认标签属性值
        static defaultProps = {
            sex: '男',
            age: 18
        }

        render() {
            const {name, age, sex} = this.props
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age + 1}</li>
                </ul>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Person name="jerry"></Person>, document.getElementById('test1'))
</script>
</body>
</html>

函数式组件使用props:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test1"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    function Person(props) {
        const {name, age, sex} = props
        return (
            <ul>
                <li>姓名:{name}</li>
                <li>性别:{age}</li>
                <li>年龄:{sex}</li>
            </ul>
        )
    }

    //对标签属性进行类型,必要性的限制
    Person.propTypes = {
        name: PropTypes.string.isRequired,
        sex: PropTypes.string,
        age: PropTypes.number,
        speak: PropTypes.func
    }

    //指定默认标签属性值
    Person.defaultProps = {
        sex: '男',
        age: 18
    }

    //2.渲染组件到页面
    ReactDOM.render(<Person name="jerry"></Person>, document.getElementById('test1'))
</script>
</body>
</html>

4.组件三大核心属性3: refs与事件处理

简介:

  • React中的refs属性是一种提供对真实DOM(组件)的引用的机制,通过这个引用,我们可以直接操作DOM(组件)。
  • 在React中,我们通常不会直接操作底层的DOM元素,而是通过在render方法中编写页面结构,并由React来组织DOM元素的更新。然而,有些情况下,我们可能需要对页面的真实DOM进行直接操作,这时就需要用到refs。
  • refs是用于访问和操作React元素(虚拟DOM元素)的一种方式。它使我们能够更加方便且准确地控制refs的设置和解除。在ref中,我们可以传递一个函数,这个函数接受React组件实例或HTML DOM元素作为参数,以使它们能在其他地方被存储和访问。
  • 对于事件处理,React中的refs也提供了相应的机制。例如,我们可以使用refs来获取HTML元素并注册事件处理函数,以便在用户与页面交互时执行特定的操作。
  • 总的来说,React的refs属性为我们提供了一种机制,使我们能够对React元素(虚拟DOM元素)进行直接操作,以及处理用户与页面交互的事件。

字符串形式的ref:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Demo extends React.Component {
        showData = () => {
            const {input1} = this.refs
            alert(input1.value)
        }
        showData2 = () => {
            const {input2} = this.refs
            alert(input2.value)
        }

        render() {
            return (
                <div>
                    <input ref="input1" type="text" placeholder="点击按钮提示数据"></input>
                    <button onClick={this.showData}>点我提示左侧的数据</button>
                    <input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>

回调形式的ref:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Demo extends React.Component {
        showData = () => {
            const {input1} = this
            alert(input1.value)
        }
        showData2 = () => {
            const {input2} = this
            alert(input2.value)
        }

        render() {
            return (
                <div>
                    <input ref={(currentNode) => {this.input1 = currentNode}} type="text" placeholder="点击按钮提示数据"></input>
                    <button onClick={this.showData}>点我提示左侧的数据</button>
                    <input ref={(currentNode) => {this.input2 = currentNode}} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>

回调ref中调用次数的问题:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Demo extends React.Component {
        state = {isHot: true}

        showInfo = () => {
            const {input1} = this
            alert(input1.value)
        }

        changeWeather = () => {
            const {isHot} = this.state
            this.setState({isHot: !isHot})
        }

        saveInput = (currentNode) => {
            this.input1 = currentNode;
            console.log('@', currentNode);
        }

        render() {
            const {isHot} = this.state
            return (
                <div>
                    <h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
                    <br></br>

                    {/*<input ref={(currentNode) => {this.input1 = currentNode;console.log('@', currentNode);}} type="text"></input>*/}
                    <input ref={this.saveInput} type="text"></input>
                    <br></br>

                    <button onClick={this.showInfo}>点我提示输入的数据</button>
                    <button onClick={this.changeWeather}>点我切换天气</button>
                    <br></br>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Demo></Demo>, document.getElementById('test'))
</script>
</body>
</html>

createRef的使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Demo extends React.Component {
        // React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
        myRef = React.createRef()
        myRef2 = React.createRef()

        showData = () => {
            alert(this.myRef.current.value)
        }
        showData2 = () => {
            alert(this.myRef2.current.value)
        }

        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"></input>
                    <button onClick={this.showData}>点我提示左侧的数据</button>
                    <input ref={this.myRef2} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>

 事件处理

  • 1.通过onXxx属性指定事件处理函数(注意大小写)
    • a.React使用的是自定义(合成)事件,而不是使用的原生DOM事件 ----- 为了更好的兼容性
    • b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ----- 为了高效
  • 2.通过event.target得到发生事件的DOM元素对象-不要过度使用ref
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Demo extends React.Component {
        // React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
        myRef = React.createRef()
        myRef2 = React.createRef()

        showData = (event) => {
            console.log(event, 'showData event')
            console.log(event.target.value)
            console.log(this.myRef.current.value)
            alert(this.myRef.current.value)
        }
        showData2 = (event) => {
            console.log(event, 'showData2 event')
            alert(event.target.value)
        }

        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"></input>
                    <button onClick={this.showData}>点我提示左侧的数据</button>
                    <input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"></input>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Demo a="1" b="2"></Demo>, document.getElementById('test'))
</script>
</body>
</html>

5.收集表单数据

非受控组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Login extends React.Component {
        handleSubmit = (event) => {
            event.preventDefault()
            const {username, password} = this
            alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
        }

        render() {
            return (
                <form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
                    用户名:<input ref={c => this.username = c} type="text" name="username"></input>
                    密码:<input ref={c => this.password = c} type="password" name="password"></input>
                    <button>登录</button>
                </form>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Login></Login>, document.getElementById('test'))
</script>
</body>
</html>

受控组件 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Login extends React.Component {
        state = {
            username: '',
            password: ''
        }

        saveUsername = (event) => {
            this.setState({username: event.target.value})
        }

        savePassword = (event) => {
            this.setState({password: event.target.value})
        }

        handleSubmit = (event) => {
            event.preventDefault()
            const {username, password} = this.state
            alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
        }

        render() {
            return (
                <form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
                    用户名:<input onChange={this.saveUsername} type="text" name="username"></input>
                    密码:<input onChange={this.savePassword} type="password" name="password"></input>
                    <button>登录</button>
                </form>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Login></Login>, document.getElementById('test'))
</script>
</body>
</html>

6.高阶函数,函数柯里化

高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。

  1. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
  2. 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
  3. 常见的高阶函数有:Promise、setTimeout、arr.map()等等

函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

高阶函数,函数柯里化

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Login extends React.Component {
        state = {
            username: '',
            password: ''
        }

        saveFormData = (dateType) => {
            return (event) => {
                this.setState({[dateType]: event.target.value})
            }
        }

        handleSubmit = (event) => {
            event.preventDefault()
            const {username, password} = this.state
            alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
        }

        render() {
            return (
                <form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
                    用户名:<input onChange={this.saveFormData('username')} type="text" name="username"></input>
                    密码:<input onChange={this.saveFormData('password')} type="password" name="password"></input>
                    <button>登录</button>
                </form>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Login></Login>, document.getElementById('test'))
</script>
</body>
</html>

对象相关的知识

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    let a = 'name'

    let obj = {}
    obj[a] = 'tom'
    console.log(obj)
</script>
</body>
</html>

演示函数的柯里化

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    // function sum(a, b, c) {
    //     return a + b + c
    // }
    //
    // const result = sum(1, 2, 3)
    // console.log(result)

    function sum(a) {
        return (b) => {
            return (c) => {
                return a + b + c
            }
        }
    }

    const result = sum(1)(2)(3)
    console.log(result)
</script>
</body>
</html>

7.组件的生命周期

生命周期的三个阶段(旧)

  • 初始化阶段: 由ReactDOM.render()触发---初次渲染
  • constructor()
  • componentWillMount()
  • render()
  • componentDidMount()
  • 更新阶段: 由组件内部this.setSate()或父组件重新render触发
  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate()
  • 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
  • componentWillUnmount()

引出生命周期:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Life extends React.Component {
        state = {opacity: 1}

        death = () => {
            clearInterval(this.timer)
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        //组件挂载完毕
        componentDidMount() {
            console.log('组件挂载完毕')
            this.timer = setInterval(() => {
                let {opacity} = this.state
                opacity -= 0.1
                if (opacity <= 0) opacity = 1
                this.setState({opacity})
            }, 200)
        }

        //组件将要卸载
        componentWillUnmount() {
            console.log('组件将要卸载')
            clearInterval(this.timer)
        }

        //初始化渲染、状态更新之后
        render() {
            console.log('render')
            return (
                <div>
                    <h2 style={{opacity: this.state.opacity}}>React学不会怎么办?</h2>
                    <button onClick={this.death}>不活了</button>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Life></Life>, document.getElementById('test'))
</script>
</body>
</html>

react生命周期(旧) 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Count extends React.Component {
        constructor(props) {
            console.log('Count---constructor')
            super(props);
            this.state = {count: 0}
        }

        state = {count: 0}

        add = () => {
            const {count} = this.state
            this.setState({count: count + 1})
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        componentWillMount() {
            console.log('Count---componentWillMount')
        }

        componentDidMount() {
            console.log('Count---componentDidMount')
        }

        componentWillUnmount() {
            console.log('Count---componentWillUnmount')
        }

        render() {
            console.log('Count---render')
            const {count} = this.state
            return (
                <div>
                    <h2>当前求和为:{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>

 react生命周期(l日)_setState流程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Count extends React.Component {
        constructor(props) {
            console.log('Count---constructor')
            super(props);
            this.state = {count: 0}
        }

        state = {count: 0}

        add = () => {
            const {count} = this.state
            this.setState({count: count + 1})
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        componentWillMount() {
            console.log('Count---componentWillMount')
        }

        // 组件挂载完毕的钩子
        componentDidMount() {
            console.log('Count---componentDidMount')
        }

        // 组件将要卸载的钩子
        componentWillUnmount() {
            console.log('Count---componentWillUnmount')
        }

        //控制组件更新的“阀门”
        shouldComponentUpdate() {
            console.log('Count---shouldComponentUpdate')
            return true
        }

        //组件将要更新的钩子
        componentWillUpdate() {
            console.log('Count---componentWillUpdate')
        }

        //组件更新完毕的钩子
        componentDidUpdate() {
            console.log('Count---componentDidUpdate')
        }

        render() {
            console.log('Count---render')
            const {count} = this.state
            return (
                <div>
                    <h2>当前求和为:{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>

react生命周期(l日)_forceUpdate流程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    //创建组件
    class Count extends React.Component {
        constructor(props) {
            console.log('Count---constructor')
            super(props);
            this.state = {count: 0}
        }

        state = {count: 0}

        add = () => {
            const {count} = this.state
            this.setState({count: count + 1})
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        force = () => {
            this.forceUpdate()
        }

        //组件将要挂载的钩子
        componentWillMount() {
            console.log('Count---componentWillMount')
        }

        // 组件挂载完毕的钩子
        componentDidMount() {
            console.log('Count---componentDidMount')
        }

        // 组件将要卸载的钩子
        componentWillUnmount() {
            console.log('Count---componentWillUnmount')
        }

        //控制组件更新的“阀门”
        shouldComponentUpdate() {
            console.log('Count---shouldComponentUpdate')
            return false
        }

        //组件将要更新的钩子
        componentWillUpdate() {
            console.log('Count---componentWillUpdate')
        }

        //组件更新完毕的钩子
        componentDidUpdate() {
            console.log('Count---componentDidUpdate')
        }

        render() {
            console.log('Count---render')
            const {count} = this.state
            return (
                <div>
                    <h2>当前求和为:{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>

react生命周期(l日)_父组件render流程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript" src="../js/prop-types.js"></script>

<script type="text/babel">
    class A extends React.Component {
        state = {carName: '奔驰'}

        changeCar = () => {
            this.setState({carName: '奥迪'})
        }

        render() {
            return (
                <div>
                    <div>A</div>
                    <button onClick={this.changeCar}>换车</button>
                    <B carName={this.state.carName}></B>
                </div>
            )
        }
    }

    class B extends React.Component {
        componentWillReceiveProps(props) {
            console.log('B---componentWillReceiveProps', props)
        }

        shouldComponentUpdate() {
            console.log('B---sholdComponentUpdate')
            return true
        }

        componentWillUpdate() {
            console.log('B---componentWillUpdate')
        }

        componentDidUpdate() {
            console.log('B---componentDidUpdate')
        }

        render() {
            console.log('B---render')
            return (
                <div>我是B组件,接收到的车是:{this.props.carName}</div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<A></A>, document.getElementById('test'))
</script>
</body>
</html>

react新生命周期

生命周期的三个阶段(新)

1. 初始化阶段: 由ReactDOM.render()触发---初次渲染

  • constructor()
  • getDerivedStateFromProps
  • render()
  • componentDidMount()

2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

  • getDerivedStateFromProps
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate
  • componentDidUpdate()

3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

  • componentWillUnmount()

重要的勾子

  1. render:初始化渲染或更新渲染调用
  2. componentDidMount:开启监听, 发送ajax请求
  3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

即将废弃的勾子

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate

现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script>

<script type="text/javascript" src="../newjs/prop-types.js"></script>

<script type="text/babel">
    class Count extends React.Component {
        constructor(props) {
            console.log('Count---constructor')
            super(props);
            this.state = {count: 0}
        }

        state = {count: 0}

        add = () => {
            const {count} = this.state
            this.setState({count: count + 1})
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        force = () => {
            this.forceUpdate()
        }

        //组件将要挂载的钩子
        UNSAFE_componentWillMount() {
            console.log('Count---UNSAFE_componentWillMount')
        }

        // 组件挂载完毕的钩子
        componentDidMount() {
            console.log('Count---componentDidMount')
        }

        // 组件将要卸载的钩子
        componentWillUnmount() {
            console.log('Count---componentWillUnmount')
        }

        //控制组件更新的“阀门”
        shouldComponentUpdate() {
            console.log('Count---shouldComponentUpdate')
            return false
        }

        //组件将要更新的钩子
        UNSAFE_componentWillUpdate() {
            console.log('Count---UNSAFE_componentWillUpdate')
        }

        //组件更新完毕的钩子
        componentDidUpdate() {
            console.log('Count---componentDidUpdate')
        }

        render() {
            console.log('Count---render')
            const {count} = this.state
            return (
                <div>
                    <h2>当前求和为:{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
                </div>
            )
        }
    }

    class A extends React.Component {
        state = {carName: '奔驰'}

        changeCar = () => {
            this.setState({carName: '奥迪'})
        }

        render() {
            return (
                <div>
                    <div>A</div>
                    <button onClick={this.changeCar}>换车</button>
                    <B carName={this.state.carName}></B>
                </div>
            )
        }
    }

    class B extends React.Component {
        UNSAFE_componentWillReceiveProps(props) {
            console.log('B---componentWillReceiveProps', props)
        }

        shouldComponentUpdate() {
            console.log('B---sholdComponentUpdate')
            return true
        }

        UNSAFE_componentWillUpdate() {
            console.log('B---UNSAFE_componentWillUpdate')
        }

        componentDidUpdate() {
            console.log('B---componentDidUpdate')
        }

        render() {
            console.log('B---render')
            return (
                <div>我是B组件,接收到的车是:{this.props.carName}</div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Count></Count>, document.getElementById('test'))
</script>
</body>
</html>

react生命周期(新)_getDerivedStateFromProps

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script>

<script type="text/javascript" src="../newjs/prop-types.js"></script>

<script type="text/babel">
    class Count extends React.Component {
        constructor(props) {
            console.log('Count---constructor')
            super(props);
            this.state = {count: 0}
        }

        state = {count: 0}

        add = () => {
            const {count} = this.state
            this.setState({count: count + 1})
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        force = () => {
            this.forceUpdate()
        }

        static getDerivedStateFromProps(props, state) {
            console.log('Count---getDerivedStateFromProps', props, state)
            return props
        }

        // 组件挂载完毕的钩子
        componentDidMount() {
            console.log('Count---componentDidMount')
        }

        // 组件将要卸载的钩子
        componentWillUnmount() {
            console.log('Count---componentWillUnmount')
        }

        //控制组件更新的“阀门”
        shouldComponentUpdate() {
            console.log('Count---shouldComponentUpdate')
            return true
        }

        //组件更新完毕的钩子
        componentDidUpdate() {
            console.log('Count---componentDidUpdate')
        }

        render() {
            console.log('Count---render')
            const {count} = this.state
            return (
                <div>
                    <h2>当前求和为:{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Count count={199}></Count>, document.getElementById('test'))
</script>
</body>
</html>

 react生命周期(新)_getSnapshotBeforeUpdate

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script>

<script type="text/javascript" src="../newjs/prop-types.js"></script>

<script type="text/babel">
    class Count extends React.Component {
        constructor(props) {
            console.log('Count---constructor')
            super(props);
            this.state = {count: 0}
        }

        state = {count: 0}

        add = () => {
            const {count} = this.state
            this.setState({count: count + 1})
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        force = () => {
            this.forceUpdate()
        }

        static getDerivedStateFromProps(props, state) {
            console.log('Count---getDerivedStateFromProps', props, state)
            return null
        }

        getSnapshotBeforeUpdate() {
            console.log('Count---getSnapshotBeforeUpdate')
            return 'atguigu'
        }

        // 组件挂载完毕的钩子
        componentDidMount() {
            console.log('Count---componentDidMount')
        }

        // 组件将要卸载的钩子
        componentWillUnmount() {
            console.log('Count---componentWillUnmount')
        }

        //控制组件更新的“阀门”
        shouldComponentUpdate() {
            console.log('Count---shouldComponentUpdate')
            return true
        }

        //组件更新完毕的钩子
        componentDidUpdate(preProps, preState, snapshotValue) {
            console.log('Count---componentDidUpdate', preProps, preState, snapshotValue)
        }

        render() {
            console.log('Count---render')
            const {count} = this.state
            return (
                <div>
                    <h2>当前求和为:{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
                </div>
            )
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Count count={199}></Count>, document.getElementById('test'))
</script>
</body>
</html>

react生命周期(新)_getSnapshotBeforeUpdate的使用场景

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .list {
            width: 200px;
            height: 150px;
            background-color: skyblue;
            overflow: auto;
        }

        .news {
            height: 30px;
        }
    </style>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script>

<script type="text/javascript" src="../newjs/prop-types.js"></script>

<script type="text/babel">
    class NewsList extends React.Component {
        state = {newsArr: []}

        componentDidMount() {
            setInterval(() => {
                const {newsArr} = this.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(<NewsList></NewsList>, document.getElementById('test'))
</script>
</body>
</html>

8.虚拟DOM与DOM Diffing算法

  1. 虚拟DOM中key的作用:
    1. 简单的说: key是虚拟DOA对象的标识,在更新显示时key起着极其重要的作用。
    2. 详细的说:当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】 ,随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下;
      1. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
        1. 若虚拟DOM中内容没变,直接使用之前的真实DOM
        2. 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
      2. 旧虚拟DOM中未找到与新虚拟DOM相同的key根据数据创建新的真实DOM,随后渲染到到页面
  2. 用index作为key可能会引发的问题:
    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新· ==>·界面效果没问题,但效率低。
    2. 如果结构中还包含输入类的DOM:会产生错误DOM更新==>界面有问题。
    3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。 
  3. 开发中如何选择key? :
    1. 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
    2. 如果确定只是简单的展示数据,用index也是可以的。 

验证Diffing算法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .list {
            width: 200px;
            height: 150px;
            background-color: skyblue;
            overflow: auto;
        }

        .news {
            height: 30px;
        }
    </style>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script>

<script type="text/javascript" src="../newjs/prop-types.js"></script>

<script type="text/babel">
    class Time extends React.Component {
        state = {date: new Date()}

        componentDidMount() {
            setInterval(() => {
                this.setState({
                    date: new Date()
                })
            },1000)
        }

        render() {
            return (
                <div>
                    <h1>hello</h1>
                    <input type="text"></input>
                    <span>现在是:{this.state.date.toTimeString()}</span>
                </div>
            );
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Time></Time>, document.getElementById('test'))
</script>
</body>
</html>

key的作用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .list {
            width: 200px;
            height: 150px;
            background-color: skyblue;
            overflow: auto;
        }

        .news {
            height: 30px;
        }
    </style>
</head>
<body>
<!--准备好一个“容器”-->
<div id="test"></div>

<!--引入react核心库-->
<script type="text/javascript" src="../newjs/react.development.js"></script>
<!--引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../newjs/react-dom.development.js"></script>
<!--引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../newjs/babel.min.js"></script>

<script type="text/javascript" src="../newjs/prop-types.js"></script>

<script type="text/babel">
    // 慢动作回放----使用index索引值做为key
    // 初始数据:
    //     {id:1,name:'小张',age:18},
    //     {id:2,name:'小李',age:19},
    // 初始的虚拟DOM:
    //     <li key=0>小张---18</li>
    //     <li key=1>小李---19</li>
    // 更新后的数据:
    //     {id:3,name:'小王',age:20},
    //     {id:1,name:'小张',age:18},
    //     {id:2,name:"小李',age:19},
    // "更新数据后的虚拟DOM:
    //     <li key=0>小王---20</li>
    //     <li key=1>小张---18</li>
    //     <li key=2>小李---19</li>

// ---------------------------------------------------

    // 慢动作回放----使用id唯一标识做为key
    // 初始数据:
    //     {id:1,name:'小张',age:18},
    //     {id:2,name:'小李',age:19},
    // 初始的虚拟DOM:
    //     <li key=1>小张---18</li>
    //     <li key=2>小李---19</li>
    // 更新后的数据:
    //     {id:3,name:'小王',age:20},
    //     {id:1,name:'小张',age:18},
    //     {id:2,name:"小李',age:19},
    // "更新数据后的虚拟DOM:
    //     <li key=3>小王---20</li>
    //     <li key=1>小张---18</li>
    //     <li key=2>小李---19</li>
    class Person extends React.Component {
        state = {
            persons: [
                {id: 1, name: '小张', age: 18},
                {id: 2, name: '小李', age: 19},
            ]
        }

        add = () => {
            const {persons} = this.state
            const p = {id: persons.length + 1, name: '小王', age: 20}
            this.setState({persons: [p, ...persons]})
        }

        render() {
            return (
                <div>
                    <h2>展示人员信息</h2>
                    <button onClick={this.add}>添加一个小王</button>
                    <h3>使用index索引值作为key</h3>
                    <ul>
                        {
                            this.state.persons.map((personObj, index) => {
                                return <li key={index}>{personObj.name}---{personObj.age}<input type="text"></input></li>
                            })
                        }
                    </ul>
                    <hr></hr>
                    <hr></hr>
                    <h3>使用id(数据的唯一标识)作为key</h3>
                    <ul>
                        {
                            this.state.persons.map((personObj) => {
                                return <li key={personObj.id}>{personObj.name}---{personObj.age}<input type="text"></input></li>
                            })
                        }
                    </ul>
                </div>
            );
        }
    }

    //2.渲染组件到页面
    ReactDOM.render(<Person></Person>, document.getElementById('test'))
</script>
</body>
</html>

运行结果:


http://www.niftyadmin.cn/n/5060981.html

相关文章

目标检测YOLO实战应用案例100讲-雾天场景下低能见度图像 目标检测(下)

目录 雾天场景目标检测算法分析对比 4.1 引言 4.2 雾天图像目标检测相关的综合评价指标分析

前端架构师之02_Node.js安装

Node.js运行环境搭建 1.1 下载和安装 Node.js是一个基于Chrome V8引擎的JavaScript代码运行环境&#xff0c;也可以说是一个运行时平台&#xff0c;提供了一些功能性的API&#xff0c;如文件操作API、网络通信API。 如果在浏览器运行JavaScript代码&#xff0c;浏览器就是Ja…

C语言 —— 函数

目录 1. 函数是什么 2. C语言中函数的分类 2.1 库函数 2.2 自定义函数 3. 函数的参数 3.1 实际参数(实参) 3.2 形式参数(形参) 4. 函数的调用 4.1 传值调用 4.2 传址调用 5. 函数的嵌套调用和链式访问 5.1 嵌套调用 5.2 链式访问 6. 函数的声明和定义 6.1函数声明…

滴答定时器

1.定时与计数的本质 2.滴答定时器的原理 1.向下计数&#xff0c;24位的计数器。滴答定时器属于内核。 每来一个脉冲计数值减一。当为零时。继续把重载寄存器给计数值。然后每来一个脉冲减一。 可以不停重复次操作。 控制寄存器&#xff1a;时钟的选择(bit2&#xff09;&…

Ubuntu安装zsh之后搜狗起不来

1. 问题描述 装了Ubuntu22.04后&#xff0c;先装了搜狗&#xff0c;再装了zsh&#xff0c;装完zsh之后发现搜狗起不来了&#xff0c;重装搜狗和fcitx之后还是起不来&#xff0c;在此记录解决过程。 2. 解决方法 参考博客: 配置zsh后&#xff0c;无法通过 DBus 连接到 Fcitx,…

FFmpeg 命令:从入门到精通 | 查看帮助文档

FFmpeg 命令&#xff1a;从入门到精通 | 查看帮助文档 FFmpeg 命令&#xff1a;从入门到精通 | 查看帮助文档FFmpeg 库模块ffmpeg 命令查看帮助文档ffplay 命令查看帮助文档ffprobe 命令查看帮助文档注意事项 FFmpeg 命令&#xff1a;从入门到精通 | 查看帮助文档 FFmpeg 库模…

Vue定义全局组件的方式

Vue.js是一种流行的JavaScript框架&#xff0c;用于构建交互式的Web应用程序。Vue提供了一种简单而灵活的方式来定义和使用组件。在本文中&#xff0c;我们将探讨Vue中定义全局组件的三种方式&#xff0c;让你能够更好地理解和使用Vue组件。 引言 组件是Vue应用程序的基本构建…

当面试被问到jvm(Java虚拟机)时,如和将面试官引入自己的节奏?

本文目录 前言快问快答抛砖引玉锦上添花好书推荐总结 前言 作为一名Java开发工程师&#xff0c;不管是校招还是社招jvm一定是必问必会的知识点。虽然说真正开发中用到的不多&#xff0c;甚至可以说用不到&#xff08;对于刚入行或者Java初级&#xff09;&#xff0c;但是当面试…