【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. 组件中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>

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>

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>

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'))

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'))

第二种形式 – 回调函数形式的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'))

第三种形式 – 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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值