40. B站 react三大属性1:state html源码 - yiqunkeke/react-jianshu-shangguigu-zty GitHub Wiki

<!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>hello_react</title>
    <!-- 引入react,为了使用 React对象  -->
    <script src="js/react.development.js"></script>
    <!-- 引入 react-dom, 为了使用 ReactDOM 对象 -->
    <script src="js/react-dom.development.js"></script>
    <!-- 引入 babel, 为了 解析 JSX -->
    <script src="js/babel.min.js"></script>
</head>
<body>
   <div id="test"></div>

   <!-- <button id="btn1">按钮1</button>
   <button id="btn2">按钮2</button>
   <button onclick="demo()">按钮3</button> -->

   <!-- 1. 函数式组件 -->
   <!-- <script type="text/babel">
        // 创建组件
        // 函数作为组件:函数名必须大写
        function Demo() {
            return <h2>hello,react</h2>
        }
        // 把组件渲染到页面
        // 使用函数组件时,需要使用标签,且标签必须闭合
        ReactDOM.render(<Demo/>, document.getElementById('test'))
    </script>  -->
    
    <!-- 2. 复习类的相关知识 -->
    <!-- <script type="text/javascript">
        class Person {
            // 构造器方法---中的this就是通过new Person构造出的实例对象
            constructor(name, age) {
                this.name = name
                this.age = age
            }

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

        const p1 = new Person("tom", 18)
        // console.log(p1)  // Person  {}    p1是一个对象 {},前面的 Person代表这个对象是由Person类构造的。
        p1.speak()
    </script>    -->

    <!-- 3. 类式组件 -->
    <!-- <script type="text/babel">
        // 创建组件
        class Demo extends React.Component {
            // render放在了哪里?--放在类的原型对象上。供实例调用。--实例在哪里
            // render中的this是谁?---谁调用了render? Demo类的实例调用了 render---render中的this就是实例对象。又叫组件实例对象。
            // 注意,render中的this并不是指向demo类,而是指向demo类的实例。该实例是由react在使用<Demo/>标签时帮我们自动new出来的。
            render() {
                return <h2>hello,react!!!</h2>
            }
        }
        // 把组件渲染到页面
        ReactDOM.render(<Demo/>, document.getElementById('test'))
        // ReactDOM.render(<Demo/>, document.getElementById('test')) 这句,React做了什么?
        // React解析组件标签,找到了 <Demo/>组件。
        // 发现<Demo/>组件是通过类定义的。就会 new 出来该类的一个实例,然后通过该实例调用类中的render方法。
        // 将render返回的虚拟DOM转为真实Dom,呈现到页面上。
    </script> -->

    <!-- 4. 对state的理解  -->
    <!-- 复杂组件:有状态的组件叫复杂组件
         简单组件:无状态组件

         状态:  人     状态      影响       行为
                组件    状态     驱动       数据
        -->

    <!-- 5.组件实例的三大属性1:state -->
    <!-- <script type="text/babel">
        // 创建类式组件
        class Weather extends React.Component {
            
            // 构造器能接收到什么,取决于你new Weather时传的是什么。
            // 但是new这个动作是由react帮你实现的---查询官网得知:可以接收到props
            constructor(props) {
                super(props)  // 由于Weather继承自React.Component类,且在Weather类中写了构造器。则在构造器中super优先必调

                // 写构造器的目的是什么?---在类的实例对象上添加一些属性
                this.state = {
                    isHot: true
                }

            }

            // render中的this---就是组件实例对象。如果你想在类的实例对象上添加一些属性,就需要通过constructor构造器
            render() {
                console.log(this)
                return <h2>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
            }
        }
        // 将组件渲染到页面
        ReactDOM.render(<Weather/>, document.getElementById('test'))    
    </script> -->

    <!-- 6.原生事件的绑定 -->
    <!-- <script type="text/javascript">
        // 方式1
        let btn1 = document.getElementById('btn1')
        btn1.addEventListener('click', function() {
            console.log('按钮1被点击了')
        })

        // 方式2
        let btn2 = document.getElementById('btn2')
        btn2.onclick = () => {
            console.log('按钮2被点击了')
        }

        // 方式3
        function demo() {
            console.log('按钮3被点击了')
        }
    </script> -->

    <!-- 7.react绑定事件、自定义方法中的this -->
    <!-- <script type="text/babel">
        // let that
        // 创建类式组件
        class Weather extends React.Component {
            
            constructor(props) {
                super(props) 
                this.state = {
                    isHot: true
                }
                // that = this // 在构造器中缓存组件实例对象,再送出去。
            }
            // 构造器中的this是---组件实例对象

            render() {
                return <h2 onClick={demo}>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
            }
            // render中的this是---组件实例对象。因为render是我们在使用组件标签时,由react自动帮我们new 的那个实例调用的。 【通过实例调用render时,render中的this就是实例】
        }

        // 将组件渲染到页面
        ReactDOM.render(<Weather/>, document.getElementById('test'))   
        
        // 自定义函数
        function demo() {
            // console.log('标题被点击了')
            // 去修改组件实例对象上的isHot属性
            // 先去拿到组件实例对象
            console.log(this)  // undefined
            console.log(that) // 这样可以访问到外部被缓存的组件实例对象
        }
        //  为什么demo中的this是undefined?
        // 分析: demo是自定义函数,那么demo中的this应该是 window。但是由于babel默认开启了严格模式,所以 demo 中的this指向了 undefined
        // 怎么样才能让demo中的this指向组件实例对象?
        // 通过在构造器中缓存组件实例对象this--可以实现在类的方法中访问组件实例
        // 但这样做不规范。我们希望把所有类相关的方法都放在类的本身内部。
    </script> -->
    
    <!-- 8.把自定义方法放到类内部、类中方法的this-->
    <!-- <script type="text/babel">
        // 创建类式组件
        class Weather extends React.Component {
            
            constructor(props) {
                super(props) 
                this.state = {
                    isHot: true
                }
            }
            // 构造器中的this是---组件实例对象

            render() {
                // 这里的this.demo有没有被调用?---没有。this.demo只是作为回调被放在堆中。当点击事件触发时作为onClick的回调被调用。此时的调用是直接调用。不是通过实例对象调用。
                // 所以demo中的this并不会指向组件实例。而会指向window或undefined。取决于是否开启了严格模式
                return <h2 onClick={this.demo}>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
            }
            // render中的this--组件实例对象

            // 一般方法:注意类不是函数体,在类中定义方法,不需要加 function关键字
            demo() {
                console.log(this)   // undefined          
            }
            // 为什么构造器、render中的this都指向组件实例对象。而在demo中的this却是undefined?
            // 类中的方法默认开启了局部严格模式。当demo作为onClick的回调,从堆中被直接调用时,demo中的this就指向了undefined.
        }

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

    <!--9.非严格模式this的指向  -->
    <!-- <script type="text/javascript">
        function demo() {
            console.log(this) // Window
        }
        demo()
    </script> -->

    <!--10.严格模式this的指向  -->
    <!-- <script type="text/javascript">
        function demo() {
            'use strict'
            console.log(this) // undefined
        }
        demo()
    </script> -->
   
    <!-- 11.解决类中this指向 -->
    <!-- <script type="text/babel">
        // 创建类式组件
        class Weather extends React.Component {

            constructor(props) {
                super(props) 
                this.state = {
                    isHot: true
                }
                // 赋值语句:右侧--this是组件实例对象。this.demo放在哪里?---类的原型对象上
                // bind语句返回一个新函数,且这个新函数中的this被指向了参数中的this。
                // 参数中的this是--在构造器中,是组件实例对象。所以右边得到一个新函数,且新函数中this指向组件实例。

                // 把新函数赋值给了组件实例上的demo属性。
                this.demo = this.demo.bind(this)
            }

            render() {
                // 这里的this.demo调用的是原型上的还是组件实例自身上的?
                // ---自身。因为按照原型链查找规则,自身有就不会再查找原型链
                return <h2 onClick={this.demo}>今天天气很{this.state.isHot ? '炎热':'凉爽'}</h2>
            }
            
            // demo放在哪里?--类的原型对象上
            demo() {
                console.log(this)   
            }
            
        }

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

    <!-- 12.setState的使用 -->
    <!-- <script type="text/babel">
        // 创建类式组件
        class Weather extends React.Component {
            
            constructor(props) {
                super(props) 
                this.state = {
                    isHot: true,
                    wind: '微风'
                }
                this.demo = this.demo.bind(this)
            }

            render() {
                const {isHot, wind} = this.state
                return <h2 onClick={this.demo}>今天天气很{isHot ? '炎热':'凉爽'}, {wind}</h2>
            }
            
            demo() {
                const {isHot} = this.state
                this.state.isHot = !isHot
                
                // 严重注意:在react中,更新state的值必须使用setState()API,且更新是一种合并,不是替换
                this.setState({
                    isHot: !isHot
                }) 

                // 严重注意:在react中,不能直接修改state。下面的代码就是直接修改state
                // console.log(this.state.isHot) 
            }
            
        }

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

    <!-- 13.类的小技巧 -->
    <!-- <script type="text/javascript">
        class Car {
            constructor(name, price) {
                this.name = name
                this.price = price
            }

            // 在类中可以直接写赋值语句。
            // 下面代码的含义是:给类的所有实例都添加一个属性,属性名为a,属性值为1
            a = 1
        }
        const c1 = new Car('奔驰C63', 199)
        const c2 = new Car('宝马', 299)
        console.log(c1)
        console.log(c2)
        // 通过这个技巧,我们可以简写类中的state
    </script> -->

    <!-- 14.简写state、简写类组件 -->
    <script type="text/babel">
        // 创建类式组件
        class Weather extends React.Component {
            
            // 为什么要写构造器?---为了给组件实例的state属性初始化、 为了解决类中方法this指向
            // 不通过构造器也可以实现这两个目的。
            // constructor(props) {
            //     super(props) 

            //     this.state = {
            //         isHot: true,
            //         wind: '微风'
            //     }
            //     this.demo = this.demo.bind(this)
            // }

            // 在类中直接写赋值语句--实现:给所有的组件实例自身都添加state属性
            state = {
                isHot: true,
                wind: '微风'
            }

            render() {
                const {isHot, wind} = this.state
                // 这里的demo调用的是组件实例自身的demo,原型链上不再有demo
                return <h2 onClick={this.demo}>今天天气很{isHot ? '炎热':'凉爽'}, {wind}</h2>
            }
            

            // 在类中写赋值语句:给组件实例自身添加demo属性。值是一个箭头函数。
            // demo函数放在了哪里?----组件实例对象自身。不再是放在类的原型对象上。

            // 程序员在类中写的demo方法、demo1、demo2都是作为事件的回调函数调用的。是一种直接调用。就会存在this指向为undefined的情况。
            // 因为在使用组件标签时,实例是由react帮我们自动new的,且只调用了实例.render。
            // react并不会帮你再调用写的其他方法如demo、demo1、demo2。这就一定会导致类中这些方法this一定无法指向组件实例。

            // 所以,程序员以后在类中写方法,直接写成赋值语句 + 箭头函数形式。
            // 可以在实例自身添加demo属性,值是一个箭头函数,箭头函数中this指向类中this。类中this恰好就是组件实例。这样的话,类中方法的this就不会丢失,而是一定会指向组件实例。
            demo = () => {
                // console.log(this)  // 确实指向组件实例
                const {isHot} = this.state
                this.state.isHot = !isHot             
                this.setState({
                    isHot: !isHot
                }) 
              
            }
            // 箭头函数中,没有this。如果箭头函数中使用了this,则this指向箭头函数外部的this。
            

            // demo1放在了哪里--类的原型对象上
            demo1() {}
            // demo2放在了哪里--类的原型对象上
            demo2() {}
        }

        // 将组件渲染到页面
        ReactDOM.render(<Weather/>, document.getElementById('test'))   
    </script>
</body>
</html>
⚠️ **GitHub.com Fallback** ⚠️