React 生命周期
生命周期函数也叫作:生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
通过一个案例来学习
首先,在 render
中不要写 setState()
,不然会死循环的,因为你执行 setState
就会触发 render()
下面介绍两个生命周期函数:
在如下的例子中有使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <script type="text/babel"> class Life extends React.Component{
state = {opacity:1}
death = ()=>{ ReactDOM.unmountComponentAtNode(document.getElementById('test')) }
componentDidMount(){ console.log('componentDidMount'); this.timer = setInterval(() => { let {opacity} = this.state opacity -= 0.1 if(opacity <= 0) opacity = 1 this.setState({opacity}) }, 200); }
componentWillUnmount(){ clearInterval(this.timer) }
render(){ console.log('render'); return( <div> <h2 style={{opacity:this.state.opacity}}>React学不会怎么办?</h2> <button onClick={this.death}>不活了</button> </div> ) } } ReactDOM.render(<Life/>,document.getElementById('test')) </script>
|
生命周期流程图(旧)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
| <script type="text/babel">
class Count extends React.Component{
constructor(props){ console.log('Count---constructor'); super(props) this.state = {count:0} }
add = ()=>{ const {count} = this.state this.setState({count:count+1}) }
death = ()=>{ ReactDOM.unmountComponentAtNode(document.getElementById('test')) }
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> ) } }
class A extends React.Component{ state = {carName:'奔驰'}
changeCar = ()=>{ this.setState({carName:'奥拓'}) }
render(){ return( <div> <div>我是A组件</div> <button onClick={this.changeCar}>换车</button> <B carName={this.state.carName}/> </div> ) } }
class B extends React.Component{ componentWillReceiveProps(props){ console.log('B---componentWillReceiveProps',props); }
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> ) } }
ReactDOM.render(<Count/>,document.getElementById('test')) </script>
|
UNSAFE 的理解
这是官网上对于 UNSAFE 的解释,异步渲染之更新
生命周期流程图(新)
新旧对比
新的生命周期:弃用了原来的三个带 will
的生命周期
增加了两个生命周期
static getDerivedStateFromProps
1 2 3 4 5
| static getDerivedStateFromProps(props,state){ console.log('getDerivedStateFromProps',props,state); return null }
|
getSnapshotBeforeUpdate 获取快照
1 2 3 4 5
| getSnapshotBeforeUpdate(){ console.log('getSnapshotBeforeUpdate'); return '快照' }
|
使用场景如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <script type="text/babel"> class NewsList extends React.Component{
state = {newsArr:[]}
componentDidMount(){ setInterval(() => { const {newsArr} = this.state const news = '新闻'+ (newsArr.length+1) this.setState({newsArr:[news,...newsArr]}) }, 1000); }
getSnapshotBeforeUpdate(){ return this.refs.list.scrollHeight }
componentDidUpdate(preProps,preState,height){ this.refs.list.scrollTop += this.refs.list.scrollHeight - height }
render(){ return( <div className="list" ref="list"> { this.state.newsArr.map((n,index)=>{ return <div key={index} className="news">{n}</div> }) } </div> ) } } ReactDOM.render(<NewsList/>,document.getElementById('test')) </script>
|
Diff 算法
- 匹配的最小力度是标签
- 标签中的标签也会进行
diff
算法的比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <script type="text/babel"> class Time extends React.Component { state = { date: new Date() };
componentDidMount() { setInterval(() => { this.setState({ date: new Date(), }); }, 1000); }
render() { return ( <div> <h1>hello</h1> <input type="text" /> <span> 现在是:{this.state.date.toTimeString()} <input type="text" /> </span> </div> ); } }
ReactDOM.render(<Time />, document.getElementById("test")); </script>
|
key 的作用
- 用来配合
diff
算法的
diff
先检测 key
值,如果相等的话,就检测内容
- 如果不相等的话 ,直接生成新的
DOM
- 如果在节点里有输入型的 DOM 节点,通过
index
作为 key
的话,可能会发生如下的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| index 作为 key 值 初始数据: {id:1,name:'小张',age:18}, {id:2,name:'小李',age:19}, 初始的虚拟DOM: <li key=0>小张---18<input type="text"/></li> <li key=1>小李---19<input type="text"/></li>
更新后的数据: {id:3,name:'小王',age:20}, {id:1,name:'小张',age:18}, {id:2,name:'小李',age:19}, 更新数据后的虚拟DOM: <li key=0>小王---20<input type="text"/></li> <li key=1>小张---18<input type="text"/></li> <li key=2>小李---19<input type="text"/></li>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| <script type="text/babel">
class Person extends React.Component{
state = { persons:[ {id:1,name:'小张',age:18}, {id:2,name:'小李',age:19}, ] }
add = ()=>{ const {persons} = this.state const p = {id:persons.length+1,name:'小王',age:20} this.setState({persons:[p,...persons]}) }
render(){ return ( <div> <h2>展示人员信息</h2> <button onClick={this.add}>添加一个小王</button> <h3>使用index(索引值)作为key</h3> <ul> { this.state.persons.map((personObj,index)=>{ return <li key={index}>{personObj.name}---{personObj.age}<input type="text"/></li> }) } </ul> <hr/> <hr/> <h3>使用id(数据的唯一标识)作为key</h3> <ul> { this.state.persons.map((personObj)=>{ return <li key={personObj.id}>{personObj.name}---{personObj.age}<input type="text"/></li> }) } </ul> </div> ) } }
ReactDOM.render(<Person/>,document.getElementById('test')) </script>
|