状态(state)
状态就是组件描述某种显示情况的数据,由组件自己设置和更改,也就是所组件自己维护,目的就是为了在不同状态下使组件的显示不同
在组件中只能通过getInitialState的钩子函数来给组件挂载初始状态,在组件内部通过this.state获取
this.props和this.state是纯js对象,在vue中,$data属性是利用Object.defineProperty处理过的,更改$data的数据的时候会触发数据的getter和setter,但是React中没有做这样的处理,如果直接更改的话,React是无法得知的,所以需要使用特殊的更改状态的方法
setState(params)
在setState中传入一个对象,就会将组件的状态中键值对的部分更改,还可以传入一个函数,这个回调函数必须返回像上面方式一样的一个对象,函数可以接收prevState和props
实现下拉菜单的方式
1. 通过数据来控制元素的行内样式中display
<ul style={{display:isMenuShow?'block':'none'}}><li>国内新闻</li></ul>
<ul className={isMenuShow?'show':'hide'}><li>国内新闻</li></ul>
2. 根据数据控制是否渲染该节点、组件
{ isMenuShow?<ul><li>国内新闻</li></ul>:'' }
3. 通过ref对dom、组件进行标记,在组件内部通过this.refs获取到之后,进行操作
<ul ref='content'><li>国内新闻</li></ul>this.refs.content.style.display = this.state.isMenuShow?'block':'none'
属性和状态的对比
相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)
不同点:
1. 属性能从父组件获取,状态不能
2. 属性可以有父组件修改,状态不能
3. 属性能在内部设置默认值,状态不可以
4. 属性不在组件内部修改,状态要改
5. 属性能设置子组件初始值,装填不可以
6. 属性可以修改子组件的值,状态不可以
状态只和自己相关,由自己维护
属性不要自己修改,可以从父组件获取,也可以给子组件设置
组件在运行时自己需要修改的数据其实就是状态而已
父子组件传参的交互
我们经常会令父组件将自己的某一条状态传递给子组件,这个时候,当父组件的状态更改的时候,子组件接收到的属性就会发送改变,触发render重新执行
也就是说state更改的时候(使用setState),会触发render重新执行,属性更改的时候,也能做到这一点
组件的生命周期
组件是一个构造器,每一次使用组件都相当于在实例化组件,这个时候,组件就会经历一次生命周期,从实例化实例开始到这个实例销毁的时候,都是一个完整的生命周期
组件的生命周期,我们会分为三个阶段,初始化、运行中、销毁
初始化阶段
1. 实例化组件之后,组件的getDefaultProps钩子函数会执行
这个钩子函数的目的是为组件的实例挂载默认的属性
这个钩子函数只会执行一次,也就是说,只在第一次实例化的时候执行,创建出所有实例共享的默认属性,后面再实例化的时候,不会执行getDefaultProps,直接使用已有的共享的默认属性
理论上来说,写成函数返回对象的方式,是为了防止实例共享,但是React专门为了让实例共享,只能让这个函数只执行一次
组件间共享默认属性会减少内存空间的浪费,而且也不需要担心某一个实例更改属性后其他的实例也会更改的问题,因为组件不能自己更改属性,,而且默认属性的优先级低
2. 执行getInitialState为实例挂载初始状态,且每次实例化都会执行,也就是说,每一个组件实例都拥有自己独立的状态
3. 执行componentWillMount,相当于vue里的created+beforeMount,这里是在渲染前最后一次更改数据的机会,在这里更改不会触发render的重新执行,在这里做数据的获取
4. 执行render,渲染dom
5. 执行componentDidMount,相当于vue里的mouted,多用于操作真实dom
运行中阶段
当组件mount到页面中之后,就进入了运行中阶段,在这有5个钩子函数,但这5个钩子函数只有数据(属性、状态)发生改变的时候才会执行
1. componentWillReceiveProps
当父组件给子组件传入的属性改变的时候,子组件的这个函数才会执行
当执行的时候,函数接收的第一个参数是子组件接收到的新参数,这个时候,新参数还没有同步到this.props上,多用于判断新属性和原有属性的变化后更改组件的状态
2. 接下来会执行shouldComponentUpdated,这个函数的作用
当属性或状态发送改变后控制组件是否更新,提高性能,返回true就更新,否则不更新,默认返回true
接收nextProp、nextState,根据新属性状态和原属性状态进行对比,判断后控制是否更新
3. componentWillUpdate,在这里,组件马上就要重新render了,多做一些准备工作,千万不要在这里修改状态,否则会死循环
相当于vue中的beforeUpdate
4. render,重新渲染dom,不能修改状态,会死循环
5. componentDidUpdate,在这里新的dom结构产生,不能修改状态,会死循环
销毁阶段
当组件被销毁之前,会触发componentWillUnmount
相当于vue里的beforeDestroy,所以会执行一些事件
为什么vue中有beforeDestroy,而React却没有?
vue在调用$destroy方法的时候就会执行beforeDestroy,然后组件被销毁,这个时候组件的结构还存在于页面结构中,也就是说如果想要对残留的dom结构进行处理必须在destroyed处理,但是React执行完componentWillUNmount之后吧事件、数据、dom都全部处理掉了,所以根本不需要其他的钩子函数了
怎么样就算组件被销毁:
1. 当父组件从渲染这个子组件变成不渲染这个子组件的时候,子组件相当于被销毁
2. 调用ReactDOM.unmountComponentAtNode(node)方法来将某节点中的组件销毁
react中的事件对象
React中对于事件进行了处理,解决了一些兼容性问题,React事件对象上面挂载着nativeEvent,这个就是原生的事件对象
React对事件对象做了优化,如果不取值的话,只都是null