• 【React】第三部分 组件实例的三大核心属性


    React】第三部分 组件实例的三大核心属性



    3. 组件实例的三大核心属性

    3.1 state

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

    下面就举一个简单的例子来认识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>state</title>
    </head>
    <body>
        <!-- 准备好一个容器 -->
        <div id="box"></div>
    
        <!-- 下面需要按顺序进行引入 -->
        <!-- 引入React核心库 -->
        <script src="./react.development.js" type="text/javascript"></script>
        <!-- 引入react-dom, 用来支持react去操作dom -->
        <script src="./react-dom.development.js" type="text/javascript"></script>
        <!-- 引入babel, 用来将jsx转化为js -->
        <script src="./babel.min.js" type="text/javascript"></script>
        <!-- 这里需要注意将type写成 text/babel-->
        <script type="text/babel" >
            class Weather extends React.Component{
                constructor(props){
                    // 这行代码先不管,这里必须要写,后面会说
                    super(props)
                    // 初始化一个数据
                    this.state = {isHot:true}
                    // 解决changeWeather函数中this为undefined
                    this.changeWeather = this.changeWeather.bind(this)
                    // 解释一下上述的代码
                    /* 
                        左侧this.changeWeather表示的是:在Weather的实例对象上添加一个属性为changeWeather
                        右侧this.changeWeather是去找这个函数,自身没有去原型对象上找,
                        找到了使用bind返回一个新的函数,并且修改this的指向
                        最后把这个函数赋值给实例对象上的changeWeather
                     */
                }
                render(){
                    const {isHot} = this.state
                    return(
                        // 此时这里的this.changeWeather找的是实例对象上的,而不是原型对象上的
                        <h1 onClick={this.changeWeather}>今天天气很{isHot ? '热' : '冷'}</h1>
                    )
                }
    
                // 定义一个函数用来切换天气状态
                changeWeather(){
                    /*
                        这里有个坑,此处的this为undefined,为什么呢?
                        分析: 
                        changeWeather函数它是放在Weather原型对象上,供它的实例对象使用
                        由于在render函数中changeWeather函数是作为onClick的回调,是直接调用
                        在类中的方法默认是开启局部严格模式.所以changeWeather函数中的this为undefined
    
                        这里举个例子大家就更明白了
                        class demo {
                                say(){
                                    console.log(this);
                                }
                            }
    
                        const d = new demo()
                        d.say()  // 此时this指向的该类的实例对象
                        // 下面我做了一个操作
                        const x = d.say
                        x() // 此时this为undefined
    
                        根据上述同理可得为什么changeWeather中this的指向为undefined
                     */
                    console.log(this);
                    // 需要调用setState对state中的数据进行修改,不能直接修改
                    this.setState({isHot:!this.state.isHot})
                }
            }
    
            ReactDOM.render(<Weather/>,document.getElementById('box'))
        </script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    在这里插入图片描述

    注意点:

    1. 组件中render方法中的this也指向组件实例对象(也就是类的实例对象)

    2. constructor构造器函数中的this也指向组件实例对象(也就是类的实例对象)

    3. 自定义组件中方法的this为undefined的解决办法?

      (1) 强制绑定this,通过函数对象的bind()

      (2) 箭头函数

    4. 状态数据不能够直接去修改或者更新

    3.2 简化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>05-简化state写法</title>
    </head>
    <body>
        <!-- 准备好一个容器 -->
        <div id="box"></div>
    
        <!-- 下面需要按顺序进行引入 -->
        <!-- 引入React核心库 -->
        <script src="./react.development.js" type="text/javascript"></script>
        <!-- 引入react-dom, 用来支持react去操作dom -->
        <script src="./react-dom.development.js" type="text/javascript"></script>
        <!-- 引入babel, 用来将jsx转化为js -->
        <script src="./babel.min.js" type="text/javascript"></script>
        <!-- 这里需要注意将type写成 text/babel-->
        <script type="text/babel" >
            class Weather extends React.Component{
                render(){
                    return (
                        <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot?'热':'冷'}</h1>
                    )
                }
    
                // 在类中可以写构造器函数,方法,也可以写赋值语句,但是不能写变量例如:let a = xx
                // 在类中写赋值语句它会绑定在该类的实例对象上
                // 如果是写自定义函数它会在该类的原型对象上,供实例对象使用,二者要区分
                state = {isHot:true}
    
                // 自定义函数 --- 这里需要使用赋值语句配合箭头函数
                // 赋值语句将其绑在实例对象上,箭头函数用于改变this的指向
                changeWeather = ()=>{
                    console.log(this);
                    // setState函数是合并数据而不是替换原有的数据
                    this.setState({isHot:!this.state.isHot})
                }
            }
    
            ReactDOM.render(<Weather/>,document.getElementById('box'))
    
        </script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    3.3 props

    1. 每个组件对象都会有props属性

    2. 组件标签的所有属性都会保存在props中

    3. 通过标签属性从组件外向组件内传递变化的数据

    4. 注意:组件内部不要修改props数据

    5. 读取传入的数据this.props.xxx

    <!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>props</title>
    </head>
    <body>
        <!-- 准备好一个容器 -->
        <div id="box1"></div>
        <div id="box2"></div>
        <div id="box3"></div>
    
        <!-- 下面需要按顺序进行引入 -->
        <!-- 引入React核心库 -->
        <script src="./react.development.js" type="text/javascript"></script>
        <!-- 引入react-dom, 用来支持react去操作dom -->
        <script src="./react-dom.development.js" type="text/javascript"></script>
        <!-- 引入babel, 用来将jsx转化为js -->
        <script src="./babel.min.js" type="text/javascript"></script>
        <!-- 引入prop-types, 用来去限制props的类型 -->
        <script src="./prop-types.js" type="text/javascript"></script>
        <!-- 这里需要注意将type写成 text/babel-->
        <script type="text/babel">
            class Demo extends React.Component{
                render(){
                    // 利用props取到传入的参数
                    let {name,age,gender} = this.props
                    return(
                        <ul>
                            <li>姓名:{name}</li>
                            <li>年龄:{age}</li>
                            <li>性别:{gender}</li>
                        </ul>
                    )
                }
            }
    
            // 指定标签属性的数据类型
            Demo.propTypes = {
                name:PropTypes.string.isRequired,
                age:PropTypes.number,
                gender:PropTypes.string,
                speak:PropTypes.func
            }
            
            // 指定默认值
            Demo.defaultProps = {
                gender:'male',
                age:18
            }
    
            // 在标签中写入即可传参
            ReactDOM.render(<Demo name= 'Jack' age={18} gender="male" />,document.getElementById('box1'))
            ReactDOM.render(<Demo name="Mark" age={35} gender="female" />,document.getElementById('box2'))
            
            // 批量传递参数
            let people = {name:'Jane',age:35,gender:"male"}
            // 这是react的一个语法糖,否则按照扩展运算符是不能够去展开对象的
            ReactDOM.render(<Demo {...people}/>,document.getElementById('box3'))
    
            
        </script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    3.4 简化props

    将在class类外添加的属性移到类中

    利用static

    <!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>props</title>
    </head>
    <body>
        <!-- 准备好一个容器 -->
        <div id="box1"></div>
        <div id="box2"></div>
        <div id="box3"></div>
    
        <!-- 下面需要按顺序进行引入 -->
        <!-- 引入React核心库 -->
        <script src="./react.development.js" type="text/javascript"></script>
        <!-- 引入react-dom, 用来支持react去操作dom -->
        <script src="./react-dom.development.js" type="text/javascript"></script>
        <!-- 引入babel, 用来将jsx转化为js -->
        <script src="./babel.min.js" type="text/javascript"></script>
        <!-- 引入prop-types, 用来去限制props的类型 -->
        <script src="./prop-types.js" type="text/javascript"></script>
        <!-- 这里需要注意将type写成 text/babel-->
        <script type="text/babel">
            class Demo extends React.Component{
                render(){
                    // 利用props取到传入的参数
                    let {name,age,gender} = this.props
                    return(
                        <ul>
                            <li>姓名:{name}</li>
                            <li>年龄:{age}</li>
                            <li>性别:{gender}</li>
                        </ul>
                    )
                }
    
                // 根据上述所说的props,那么其实就是在给类身上加属性
                // 那么就可以用到static去修饰
                static propTypes = {
                    name:PropTypes.string.isRequired,
                    age:PropTypes.number,
                    gender:PropTypes.string,
                    speak:PropTypes.func
                }
                
                // 指定默认值
                static defaultProps = {
                    gender:'male',
                    age:18
                }
            }
         
            // 在标签中写入即可传参
            ReactDOM.render(<Demo name= 'Jack' age={18} gender="male" />,document.getElementById('box1'))
            ReactDOM.render(<Demo name="Mark" age={35} gender="female" />,document.getElementById('box2'))
            
            // 批量传递参数
            let people = {name:'Jane',age:35,gender:"male"}
            // 这是react的一个语法糖,否则按照扩展运算符是不能够去展开对象的
            ReactDOM.render(<Demo {...people}/>,document.getElementById('box3'))
            
            
        </script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    3.5 在函数式组件子中使用props

    在函数式组件中它本身是没有自己this,按理说是用不了这个三大核心属性,但是由于函数的特性可以传参数,所以可以使用props

    它会将标签传入的参数收集成一个对象交给props

    // 在函数式组件中使用props
            function Test (props){
                return (
                    <ul>
                        <li>姓名:{props.name}</li>
                        <li>年龄:{props.age}</li>
                        <li>性别:{props.gender}</li>
                    </ul>
                )
            }
    				// 指定标签属性的数据类型
            Test.propTypes = {
                name:PropTypes.string.isRequired,
                age:PropTypes.number,
                gender:PropTypes.string,
                speak:PropTypes.func
            }
            
            // 指定默认值
            Test.defaultProps = {
                gender:'male',
                age:18
            }
            ReactDOM.render(<Test name="LiLi" age={23} gender="male"/>,document.getElementById('box4'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.6 refs

    在组件内可以通过ref属性来标识自己

    第一种形式 – 字符串形式的ref

    这种形式是最简单的,但是官方文档说以后可能会废除这种形式

      class Demo extends React.Component{
                render(){
                    return (
                        <div>
                            <input type="text" ref="inp"/>
                            <button onClick={this.testEvent}>点击我弹窗</button>
                        </div>
                    )
                }
    
                testEvent = ()=>{
                    // 通过实例对象上的refs来获取ref所标识的节点
                    alert(this.refs.inp.value);
                }
            }
    
            ReactDOM.render(<Demo/>,document.getElementById('box'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    第二种形式 – 回调函数形式的ref

    如下代码,回调函数中的参数c表示是当前节点,this.inp = c 把当前的节点放在实例对象上

     class Demo extends React.Component{
                render(){
                    return (
                        <div>
                            <input type="text" ref={c =>this.inp = c}/>
                            <button onClick={this.testEvent}>点击我弹窗</button>
                        </div>
                    )
                }
    
                testEvent = ()=>{
                    // 到实例对象身上找
                    alert(this.inp.value);
                }
            }
    
            ReactDOM.render(<Demo/>,document.getElementById('box'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    第三种形式 – createRef创建ref容器

    需要注意:

    1. 一个容器只对应一个节点
    2. 这种形式是官方最为推荐的写法
     class Demo extends React.Component{
                // 创建容器
                box1 = React.createRef()
                box2 = React.createRef()
                render(){
                    return (
                        <div>
                            <input type="text" ref={this.box1}/>
                            <button onClick={this.testEvent} ref={this.box2}>点击我弹窗</button>
                        </div>
                    )
                }
    
                testEvent = ()=>{
                    // 在这里需要注意的是这个容器存储的结构是 {current:xxx}
                    alert(this.box1.current.value);
                }
            }
    
            ReactDOM.render(<Demo/>,document.getElementById('box'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    总结

    以上就是今天要讲的内容,希望对大家有所帮助!!!

  • 相关阅读:
    在Linux/Ubuntu/Debian中使用 `tee` 命令将输出显示在终端并写入文件中
    数据库选型与优化:策略与技巧的探讨
    机器学习——回归
    Linux小程序——进度条
    猿创征文|Redis的知识总结与项目应用
    如何在Intellij IDEA中添加JUnit单元测试
    【Docker】非root用户加入docker用户组省去sudo (三)
    【深度学习目标检测】十九、基于深度学习的芒果计数分割系统-含数据集、GUI和源码(python,yolov8)
    Docker容器内使用matplotlib.pyplot
    Java --- UDP 通信 DatagramSocket DatagramPacket 使用 完整步骤
  • 原文地址:https://blog.csdn.net/Trees__/article/details/126157314