生命周期
/*
理解:
1. 组件从创建到死亡会经历一些特定的阶段
2. React组件中包含一系列的钩子函数(生命周期回调函数),会在特定的时刻调用
3. 定义组件时,会在特定的生命周期回调函数中做特定的工作
生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
删除组件
ReactDOM.unmountComponentAtNode(document.getElementById('idiv'))
render的调用时机:
初始化渲染,状态更新
componentDidMount(){}
组件挂载完毕调用(一次)
componentWillUnmount(){}
组件将要卸载时调用
clearInterval()
清除定时器
setInterval()
创建定时器
*/
class Life extends React.Component {
state = { opacity: 1 }
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('idiv'))
}
componentDidMount() {
this.timer = setInterval(() => {
let { opacity } = this.state
opacity -= 0.1
if (opacity <= 0) {
opacity = 1
}
this.setState({ opacity: opacity })
// 简写{opacity}
}, 200)
}
componentWillUnmount() {
clearInterval(this.timer)
}
render() {
return (
<div>
<h2 style={{ opacity: this.state.opacity }}>你好吗?</h2>
<button onClick={this.death}>还可以</button>
</div>
)
}
}
生命周期(旧)
/*
1. 初始化阶段:由ReactDOM.render()触发---初次渲染
1. constructor()
2. componentWillMount()
3. render()
4.componentDidMount()======>常用,一般做一些初始化的事情,例如开启定时器,发送网络请求,订阅消息
2. 更新阶段:由组件内部this.setState()或父组件重新render触发
1. shouldComponentUpdate()
2. componentWillUpdate()
3. rendedr()======>必须使用的一个
4. componentDidUpdate()
3. 卸载组件:由ReactDOM.unmountComponentAtNode()触发
1. componentWillUnmount() ======>常用,一般做一些收尾的事情,例如关闭定时器,取消订阅消息
*/
class Count extends React.Component {
//构造器
constructor(props) {
console.log("Count---constructor")
super(props);
this.state = {
count: 0,
}
}
//自己写的回调
add = () => {
let { count } = this.state
this.setState({ count: count + 1 })
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("idiv"))
}
force = () => {
this.forceUpdate()
}
//组件将要挂载
componentWillMount() {
console.log("Count---componentWillMount")
}
//组件挂载完成
componentDidMount() {
console.log("Count---componentDidMount")
}
//组件将要卸载
componentWillUnmount() {
console.log("Count---componentWillUnmount")
}
//控制组件是否更新
shouldComponentUpdate() {
console.log("Count---shouldComponentUpdate")
return true
}
//组件将要更新
componentWillUpdate() {
console.log("Count---componentWillUpdate")
}
//组件更新完毕
componentDidUpdate() {
console.log("Count---componentDidUpdate")
}
render() {
console.log("Count---render")
const { count } = this.state
return (
<div>
<h2>当前为{count}</h2>
<button onClick={this.add}>点击+1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改,强制刷新组件</button>
</div>
)
}
}
//父组件A
class A extends React.Component {
state = {carName:'aaa'}
changeCar = ()=>{
this.setState({carName:'bbb'})
}
render() {
return (
<div>
<div>我是A</div>
<button onClick={this.changeCar}>换车</button>
<B carName = {this.state.carName}/>
</div>
)
}
}
//子组件B
class B extends React.Component {
//组件将要接受新的props的钩子(第一次不算,更新才算)
componentWillReceiveProps(){
console.log('B------componentWillReceiveProps');
}
//组件更新阀门
shouldComponentUpdate(){
console.log('B---shouldComponentUpdate')
return true
}
//组件将要更新
componentWillUpdate() {
console.log("B---componentWillUpdate")
}
//组件更新完毕
componentDidUpdate() {
console.log("B---componentDidUpdate")
}
render() {
console.log('B---render')
return (
<div>B,接受的车是{this.props.carName}</div>
)
}
}
生命周期(新)
/*
新版本中 componentWillMount,componentDidUpdate,componentWillReceiveProps 这三个需要加上前缀'UNSAFE_'(不是指安全性,是说未来版本中可能会有bug),
即UNSAFE_componentWillMount,UNSAFE_componentDidUpdate,UNSAFE_componentWillReceiveProps
1. 初始化阶段:由ReactDOM.render()触发---初次渲染
1. constructor()
2. getDerivedStateFromProps()
3. render()
4.componentDidMount()
2. 更新阶段:由组件内部this.setState()或父组件重新render触发
1. getSnapshotBeforeUpdate()
2. shouldComponentUpdate()
3. rendedr()
4. componentDidUpdate()
3. 卸载组件:由ReactDOM.unmountComponentAtNode()触发
1. componentWillUnmount()
*/
class Count extends React.Component {
//构造器
constructor(props) {
console.log("Count---constructor")
super(props);
let {count} = props
this.state = {
count: count,
}
}
//自己写的回调
add = () => {
let { count } = this.state
this.setState({ count: count + 1 })
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("idiv"))
}
force = () => {
this.forceUpdate()
}
//若state的值任何时候都取决于props,使用该方法
static getDerivedStateFromProps(props, state) {
console.log("####", props, state)
console.log("Count---getDerivedStateFromProps")
// return props
return null
}
//更新之前获取快照
getSnapshotBeforeUpdate() {
console.log('Count---getSnapshotBrforeUpdate')
// return null
return 'wxyssybs'
}
//组件挂载完成
componentDidMount() {
console.log("Count---componentDidMount")
}
//组件将要卸载
componentWillUnmount() {
console.log("Count---componentWillUnmount")
}
//控制组件是否更新
shouldComponentUpdate() {
console.log("Count---shouldComponentUpdate")
return true
}
//组件更新完毕(参数,更新前的值,不是当前,snapshotValue为保存的快照值,getSnapshotBeforeUpdate的返回值)
componentDidUpdate(preProps,preState,snapshotValue) {
console.log("Count---componentDidUpdate",preProps,preState,snapshotValue)
}
render() {
console.log("Count---render")
const { count } = this.state
return (
<div>
<h2>当前为{count}</h2>
<button onClick={this.add}>点击+1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改,强制刷新组件</button>
</div>
)
}
}
Diffing 算法
/*
1. render的时候,发现未改变的标签,则原样输出,即输出原标签
2. 发现改变的标签,则会输出新的标签
3. 检测的最小单位为一个标签
*/
key
/*
1. 作用:
简单讲:
key是虚拟DOM中对象的标识,在更新显示时key起着极其重要的作用
详细讲:
当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,规则如下:
a:旧虚拟DOM中找到了与新虚拟DOM相同的key
1. 旧虚拟DOM中内容没变,直接使用之前的真实DOM
2. 虚拟DOM内容改变,生成新的真实DOM,替换掉之前的真实DOM
b:旧虚拟DOM中未找到与新虚拟DOM相同的key
根据数据创建新的真实DOM,渲染到页面
2. 使用index作为key可能会引发的问题:
1.对数据进行逆序添加,逆序删除等破坏顺序的操作,产生没必要的DOM更新,没问题,效率低
2. 若结构中包含输入类的DOM,残生错的DOM更新,(diffing算法)
3. 若不破坏顺序的操作,仅用于展示,则可以使用index作为key
3. 如何选择?
1. 最好使用唯一标识作为key
2. 若只是简单地展示。可以用index
*/