飞道的博客

react-state状态

445人阅读  评论(0)

react属性-state状态

一 对state的理解(20)

需要理解的概念有:

  • 人->状态->行为与组件->状态->驱动视图之间的比较理解
  • 通过查看this,确认实例对象的属性内容主要包括的部分
  • 理解组件包括的三大核心属性:state、props、refs
  • 理解响应式数据与普通数据之间的差异

	<!-- 准备好一个容器 -->
    <div id="test"></div>
    <script type="text/babel">
        const username = 'Vane'
        //定义组件
        class Demo extends React.Component {
            render() {
                // 查看this对象,因为this指向的是实例对象
                // 所以可以看到实例对象的属性内容
                console.log(this);//组件实例Demo{}
                return (
                    <div>
                        <h3>你好,{username}</h3>
                    </div>
                )
            }
        }
        //组件内容没有变化,有输出但是没有渲染
        setTimeout(() =>{
        	username = "李四"
        },1000)
        //渲染组件
        ReactDOM.render(<Demo />, document.getElementById('test'))
    </script>

设置的username并不是一个响应式的数据内容,我们期望实现的是响应式数据的更新。

当前变量声明方式与响应式的方式从生活化编程理解:

  • 初始阶段都是一样的
  • 后续阶段将出现问题,没办法实现响应式数据的修改

案例:

  • 张三买了一款手机,花费3000,但没买手机屏幕保险。手机屏幕摔碎,后期不管。
  • 李四买了一款手机,花费3800,但买了手机屏幕保险。手机屏幕摔碎,不管几次,后期只要屏幕碎了,就直接换新。

二 初始化state

需要理解的概念有:

  • this中的context、props、state、refs等内容由谁协助完成
  • undefined、null、空对象的差异与区别
  • 为什么state最终需要设置成对象模式,而不是数组等数据类型(数组为有序、对象则无序)
  • 在哪里设置state,为什么在constructor中进行state的设置
  • constructor中属性与状态的代码顺序是如何
  • JSX中如何编写注释
  • state能直接渲染的数据类型有哪些
	<div id="test"></div>
    <script type="text/babel">
    	let username = "张三"
        //定义组件
      	// this中的context、props、state、refs等内容由谁协助完成?
      	// 是由父类(父组件)React.Component完成,由子类继承
        class Demo extends React.Component {
            render() {
                console.log(this); // this指向组件实例对象
                return (
                    <div>
                        <h2 >你好,{username}</h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Demo />, document.getElementById('test'))
    </script>
	<div id="test"></div>
    <script type="text/babel">
        //定义组件
        class Weather extends React.Component {
            // 构造器方法
            // 用于:给实例自身初始化属性,且可以接到new调用时传入的参数

            // 我们不光要继承父类的属性,还可能设置自己当前类的新属性
            // 所以需要利用 constructor 来进行当前类的属性传递与设置
            // state 之前打印的时候是一个实例对象的属性,
            // 也可以在构造函数中对它进行初始化设置操作
            constructor(props) {
                super(props)    // 先进行父类属性的继承接收
      			console.log(this) //实例对象
                // 才会有 this 对象的应用,所以super前是没有this对象的
                console.log(this.state)  //之前是null,有空间,但空间里没有值,undefined
                this.state = { //只能设为null或者对象(数组为有序、对象则无序)
                    isHot: true  //可以是任何数据类型
                }
            }

            render() {
                console.log(this.state.isHot);  //true
                return (
                    <div>
                    		{/* 渲染:
                    			界面中isHot并不显示,是因为数据类型的问题,现在是布尔型,不显示
                    			哪些数据类型可以在JSX中直接渲染?
                    			可以是:string/number/array、三元运算
                    			不能是:对象、函数等数据类型
                    		*/}
                        <h2 >今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
    </script>

三 react中绑定事件的写法

需要理解的概念有:

  • 原生JavaScript中事件绑定的操作方式有哪几种
  • 虚拟DOM与真实DOM转换的顺序以及DOM对象获取与事件监听
  • 利用原生模式的事件绑定尝试在React的JSX中进行测试
  • React的JSX中函数调用与函数指向差异

1.原生JavaScript中事件绑定的操作方式有哪几种

<body>
    <button id="btn1">按钮一</button>
    <button id="btn2">按钮二</button>
    <!-- demo必须加()号,如果不加,则无法触发 -->
  	<!-- js 绑定点击事件的方法 -->
    <button onclick="demo()">按钮三</button>

    <script>
        const btn1 = document.getElementById('btn1')
        const btn2 = document.getElementById('btn2')
				
        // 事件监听绑定方式
        btn1.addEventListener('click', function () {
     
            alert('按钮一被点击了')
        })

      	// onclick绑定方式
        btn2.onclick = function () {
     
            alert('按钮二被点击了')
        }

        function demo() {
     
            alert('按钮三被点击了')
        }
    </script>

2.虚拟DOM与真实DOM转换的顺序以及DOM对象获取与事件监听

<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>

    <script type="text/babel">
        //定义组件
        class Weather extends React.Component {
            constructor(props) {
                super(props)
                this.state = {
                    isHot: false
                }
            }r
            render() {
                return (
                    <div>
                        <h2 id="h2">今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h2>
                    </div>
                )
            }
        }
      	/*
        const h2 = document.getElementById('h2');
        h2.addEventListener('click', function () {
            console.log(h2)  //null
            alert('真实DOM渲染之前找不到DOM对象,h2返回的是null,所以无法实现对象监听')
        })
        */
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
        
      	h2.addEventListener('click', function () {
             alert('真实DOM渲染以后可以找到DOM对象进行事件监听')
         })
        // h2.onclick = function () {
        //     alert('真实DOM渲染以后可以找到DOM对象进行事件监听')
        // }
    </script>

3.利用原生模式的事件绑定尝试在React的JSX中进行测试

			render() {
                console.log(this);
                return (
                    <div>
                    	{/*
                    		将出错,提示是否改用驼峰式命名法:
                    		Invalid event handler property `onclick`. 
                    		Did you mean `onClick`
                    		
                    		如果采用驼峰式写法仍旧会出现如下错误:
                    		Expected `onClick` listener to be a function, 
                    		instead got a value of `string` type
                    		
                    		onclick = "demo()",但是其实onclick内容绑定的是字符串
                    		*/}
                        <h2 id="h2" οnclick="demo()">
                          今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                    		</h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
        function demo() {
            alert('事件的绑定与调用')
        }

4.React的JSX中函数调用与函数指向差异

			render() {
                console.log(this);
                return (
                    <div>
                    		{/* 
                    			1 加了小括号是函数的调用,
                    			2 不加小括号是函数的指向,
                    			3 没有加小括号其实是函数的指向,最终不能加小括号 
                    			*/}
                        <h2 id="h2" onClick={demo()}>
                          今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                    		</h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
        function demo() {
            alert('事件的绑定与调用')
        }

JSX的事件绑定注意事项:

1 react的事件有很多种,它和原生事件非常的相似,比如说onclick,ondbclick,onmousemove,但是它的命名规则是驼峰式写法,比如:onClick,onDoubleClick,onMouseMove

2 在进行事件绑定的时候,需要利用{},不能是字符串

3 {}里面不需要进行()的处理,不然则就是函数调用,而不是函数指向

四 类组件中事件回调this丢失问题

需要理解的概念有:

  • 命名函数、匿名函数中的this以及函数定义的顺序与事件触发的关系
  • 通过改变块区作用域中的变量获取this对象
  • 函数指向与函数调用以及this指向的明确
  • 模拟类中的方法被React作为事件回调去使用

1.命名函数、匿名函数中的this以及函数定义的顺序与事件触发的关系

		<script type="text/babel">
      	// ES6箭头函数也没办法找到this对象 
        // const changeWeather = () => {
        //     console.log('this:', this)  //严格模式,不指向window,this是undefined
        // }

        //定义组件
        class Weather extends React.Component {
            constructor(props) {
                super(props)
                // 先进行父类属性的继承接收
                // 才会有 this 对象的应用,所以super前是没有this对象的
                this.state = {
                    isHot: false
                }
            }

            render() {
                console.log(this);
                return (
                    <div>
                        <h2 id="h2" onClick={changeWeather}>
                            今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                        </h2>
                    </div>
                )
            }
        }

        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))

        // 命名函数,函数提升
        // function changeWeather() {
        //     console.log('this:', this);
        // }

        // 匿名函数,调用不到,需要将函数定义在代码前面
        // const changeWeather = () => {
        //     console.log('this:', this)
        // }

    </script>

2.通过改变块区作用域中的变量获取this对象

	<div id="test"></div>
    <script type="text/babel">
        let that;    //let指向组件实例对象
        const changeWeather = () => {
            console.log('this:', that)
        }
        class Weather extends React.Component {
            constructor(props) {
                super(props)
                this.state = {
                    isHot: false
                }
                that = this  //将this给到that,让that可以指向组件的实例对象
            }
            render() {
                console.log(this);
                return (
                    <div>
                        <h2 id="h2" onClick={changeWeather}>
                            今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                        </h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
    </script>

思考的问题1:如果都把事件监听回调写在组件外部,那么组件封装的意义在哪?

思考的问题2:为什么需要采用组件化开发?组件化开发的组件中应该包含哪些内容?

3.函数指向与函数调用以及this指向的明确

	<div id="test"></div>
    <script type="text/babel">
        class Weather extends React.Component {
            constructor(props) {
                super(props)
                this.state = {
                    isHot: false
                }
            }
            /*类的一般方法
            changeWeather放在哪里?
            Weather的原型对象上,通常给实例对象(组件实例)使用,通过实例可以看见
            changeWeather中的this是谁?
            通过Weather的实例调用,那么changeWeather中的this就是Weather的实例
            */
            changeWeather() {
                console.log('this:', this);
            }

            render() {
                console.log(this);
                return (
                    <div>
                        {/*
                            直接changeWeather将无法调用函数
                            需要清楚changeWeather的位置与其中的this

                            所以需要将changeWeather修改为this.changeWeather

                            但修改成this.changeWeather以后,
                            changeWeather函数中的this却为undefined
                            这是因为this.changeWeather只是指向,并不是函数调用

                            如果修改成this.changeWeather(),这个this指向的是实例对象
                            并直接调用函数,则可以打印出this对象
                         */}
                        <h2 id="h2" onClick={this.changeWeather}>
                            今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                        </h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))

4.模拟类中的方法被React作为事件回调去使用

	<script>
        class Weather {
     
            changeWeather() {
     
                console.log(this);
            }
        }

        const w = new Weather();
        // 直接调用,this指向Weather
        w.changeWeather()
        // 没有调用,只是指向
        const x = w.changeWeather;
        // 进行函数调用,this输出为undefined
        // 因为现在的x()是全局,this如果不是严格模式应该是指向window
        // 但当前是class类,所以自动严格模式,所以是undefined

        // 严格模拟:如果this指向window才进行管理,
        // 不指向window是不作以管理的
        x();
    </script>

五 构造器中写bind去解决this问题

需要理解的概念有:

  • 如何改变this指向,call、apply、bind的差异与区别
  • 如何进行组件实例属性的设置
	<div id="test"></div>
    <script type="text/babel">
        class Weather extends React.Component {
            constructor(props) {
                super(props)

                this.state = {
                    isHot: false
                }
                console.log(this) //weater实例,有changeweater
                /*
                改变this指向的几种方式:
                call与apply实现两个功能:改变this指向,并且调用函数
                1.call (,,,)
                2.apply [,,,]

                bind实现两个功能:改变this指向,返回新函数
                3.bind,谁绑定改变改的this指向
                */ 
                this.changeWeather = this.changeWeather.bind(this);//this指向组件实例
                /*
               this.changeWeather: 顺着组件实例,找到原型上的changeWeather方法
               this.changeWeather.bind:调用bind生成一个新的函数
               this.changeWeather.bind(this):并且新的函数的this已经更改成了组件实例

               返回的一个新函数赋值给this.changeWeather,也就是说放到组件实例自身上
               只不过放到组件实例自身上的函数名称刚好也叫changeWeather 也可以叫xxx

               this.changeWeather = this.changeWeather.bind(this);
                */
                // 如果编写this.xxx,则会将相应的xxx设置于组件实例当中
                // 所以在组件实例中也可以看到 changeWeather 函数
                // this.instance_prop = 'instance_prop'
            }
            changeWeather() {
                console.log('this:', this);
            }
            render() {
                console.log(this);
                return (
                    <div>
                        {/*第二种方法在进行绑定事件的时候就直接通过bind改变this指向*/}
                        <h2 id="h2" onClick={this.changeWeather}>
                            今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                        </h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
    </script>

六 setState的使用

需要理解的概念有:

  • React中不能直接修改state,需要利用setState修改state数据
  • 构造器、render函数、事件调用触发的次数,setState更新的模式,组件的复用

1.React中不能直接修改state,需要利用setState修改state数据

	<div id="test"></div>
    <script type="text/babel">
        class Weather extends React.Component {
            constructor(props) {
                super(props)
                this.state = {
                    isHot: false
                }
                this.changeWeather = this.changeWeather.bind(this);
            }
            changeWeather() {
                // console.log('changeWeather');
                // React中不允许直接进行state的修改
                // this.state.isHot = true;

                // 可以通过隐式原型链查看到React.Component所提供的setState方法
                // toggle切换
                this.setState({ isHot: !this.state.isHot })
            }
            render() {
                console.log(this);
                return (
                    <div>
                        <h2 id="h2" onClick={this.changeWeather}>
                            今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                        </h2>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
    </script>

2.构造器、render函数、事件调用触发的次数,setState更新的模式,组件的复用

	<div id="test"></div>
    <hr />
    <div id="test2"></div>
    <script type="text/babel">
        class Weather extends React.Component {
            constructor(props) {
                console.log('---constructor---') //构造器调用几次? —————— 1次
                super(props)
                this.state = {
                    isHot: false,
                    wind: '微风'
                }
                this.changeWeather = this.changeWeather.bind(this);
            }
            changeWeather() {
                console.log('changeWeather')   // changeWeather调用几次? —————— 点几次调几次
                this.setState({ isHot: !this.state.isHot })
            }
            render() {
                console.log('---render---') //render 1+n次,1是初始化那次,n是state改变的次数。
                return (
                    <div>
                        <h2 id="h2" onClick={this.changeWeather}>
                            今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                        </h2>
                        <h3>风力:{this.state.wind}</h3>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Weather />, document.getElementById('test'))
        ReactDOM.render(<Weather />, document.getElementById('test2'))
    </script>

七 state的简写方式

需要理解的概念有:

  • 类中的赋值语句
  • state的简写方式

1.类中的赋值语句

		<script type="text/javascript" >
			class Student {
				constructor(name,age){
					this.name = name
					this.age = age
				}
        // console.log('hello'); 
        // 类中无法调用console.log()
        
        // alert('hello')
        // 类中无法直接调用函数
        
		// 该行代码的含义是:
        // 给实例自身追加一个属性,名为school,值为'university'
        // 类中可以直接设置实例属性
				school = 'university'
			}
			const s1 = new Student('老刘',5)
			const s2 = new Student('老王',4)
			console.log(s1)
			console.log(s2)
		</script>

2.state的简写方式

	<!-- 准备好一个容器 -->
    <div id="test"></div>
    <script type="text/babel">
        /*
        1.在开发中,初始化state一般直接使用: state = {}
      	2 直接写成state={}以后,构造器中方法的bind(this)就不再有
      	3 那么,函数中的this再次的回到undefined状态,也不会再有this.state
      		1)可以在方法的指向过程中进行bind(this)处理
        	2)在开发中,把类中所有事件回调的函数,都写成箭头函数,且直接放在组件实例自身。
        */
        class Weather extends React.Component {
            //初始化状态
            state = { isHot: true }
         	/*
                定义了一个属性,只不过该属性类型为fn函数类型
                所以需要将普通函数改造成箭头函数
                因为在箭头函数中,this不进行改变,所以仍旧是上层的实例对象
             */
        	changeWeather = () => {
                console.log(this);
                const { isHot } = this.state
                this.setState({ isHot: !isHot })
            }
            render() {
                console.log(this)  //weater{changeweather}
                return (
                    <h2 onClick={this.changeWeather}>
                        今天天气很{this.state.isHot ? '炎热' : '凉爽'}
                    </h2>
                )
            }
           /*
            // 标准的类的一般方法,将放置于隐式原型当中
            changeWeather(){
                const { isHot } = this.state
                this.setState({ isHot: !isHot })
            }
            */
            /*
                定义了一个属性,只不过该属性类型为fn函数类型
                现在的函数类型为普通函数,this为undefined
             */
            // changeWeather = function () {
            //     console.log(this);
            //     const { isHot } = this.state
            //     this.setState({ isHot: !isHot })
            // }
        }
        ReactDOM.render(<Weather />, document.getElementById('test'))
    </script>

八 总结state

需要理解的概念有:

  • state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合,无序对象)
  • 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)
  • 强烈注意
    • 组件中render方法中的this为组件实例对象
    • 组件自定义的方法中this为undefined,如何解决?
      • 强制绑定this:通过函数对象的bind(),可以在构造器中以及在事件指向过程中进行bind()
      • 箭头函数,将类的方法改为类的属性模式,通过箭头函数不改变this指向来解决
    • 状态数据,不能直接修改或更新,需要利用setState进行状态改新
      现在的函数类型为普通函数,this为undefined
      */
      // changeWeather = function () {
      // console.log(this);
      // const { isHot } = this.state
      // this.setState({ isHot: !isHot })
      // }
      }
      ReactDOM.render(, document.getElementById(‘test’))

## 八 总结state

需要理解的概念有:

- state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合,无序对象)
- 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)
- 强烈注意
  - 组件中render方法中的this为组件实例对象
  - 组件自定义的方法中this为undefined,如何解决?
    - 强制绑定this:通过函数对象的bind(),可以在构造器中以及在事件指向过程中进行bind()
    - 箭头函数,将类的方法改为类的属性模式,通过箭头函数不改变this指向来解决
  - 状态数据,不能直接修改或更新,需要利用**setState**进行状态改新

转载:https://blog.csdn.net/weixin_57218747/article/details/117406031
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场