组件生命周期
react 谷歌调试插件: react developer tools
- 组件的生命周期
- react 版本的生命周期: 15 版本 16 版本 17 版本【主流】
- react 15.x.x 15 版本生命周期
- react 16.0.0 - 16.3.x 16 版本
- react 16.3.0 以上 17 版本
- 除 15 版本以外,生命周期分为四个阶段
- 挂载阶段
- 特点: 自动执行,执行一次
- 更新阶段
- 触发条件: 组件调用了 setState || forceUpdate
- 卸载阶段
- 错误处理阶段【 15 版本是没有的 】
挂载阶段
- constructor
- 通过 props 参数可以获得绑定在组件身上的数据
- 可以定义 state
- 可以为类中的普通函数绑定 this 指针
1 2 3 4 5 6 7 8 9 10 11 12 13
| constructor(props: P) {
super(props); this.state = { name: "yyc", }; this.handler = this.handler.bind(this); }
|
- static getDerivedStateFromProps(props,state) { return {} }
1 2 3 4 5 6 7 8 9
| static getDerivedStateFromProps(props: P, state: S) { console.log("getDerivedStateFromProps"); return { money: props.money, }; }
|
- render
- 解析 this.state & this.props
- 将 jsx 形式的虚拟 dom 转成对象形式的虚拟 dom
- render 中不允许使用 this.setState() 如何你使用了,就会栈溢出
1 2 3 4 5 6 7 8 9
| render() { return ( <div> <p> {this.state.name} </p> {/* 解析this.state */} <p> {this.props.money} </p> {/* 解析this.props */} <p ref={(el) => (this.p = el)}>asdds</p> {/* 渲染成对象形式的虚拟DOM */} </div> ); }
|
- componentDidMount
- 组件挂载结束
- 虚拟 DOM -> 真实 DOM
- 获得到了真实 dom,可以做真实 DOM 操作
- 数据请求发送
- 第三方库实例化
1 2 3 4 5 6 7 8 9 10 11 12
| componentDidMount() { this.p.style.background = "red"; fetch("http://59.110.226.77:3000/api/category") .then((data) => data.json()) .then((res) => { console.log("res", res); }) .catch((error) => Promise.reject(error)); }
|
更新阶段
- static getDerivedStateFromProps 作用同挂载阶段
1 2 3 4 5 6
| static getDerivedStateFromProps(props: P, state: S) { console.log("gdsfp"); return {}; }
|
- shouldComponentUpdate 表示组件是否应该更新
- return true 表示组件更新
- return false 表示组件不更新
- 功能
- 渲染优化: 新属性 vs 旧属性 || 新状态 vs 旧状态
- 比较手动来写
1 2 3 4 5 6 7 8 9
| shouldComponentUpdate(nextProps: P, nextState: S) { console.log("scu"); return this.state.name !== nextState.name; }
|
- render 同挂载阶段
- getSnapShotBeforeUpdate 在更新前获取快照
1 2 3 4 5 6 7
| getSnapshotBeforeUpdate = (prevProps: P, prevState: S) => { console.log("gsbu"); return 1000; };
|
- 它的返回值会传递给 componentDidUpdate 的第三个参数
- componentDidUpdate
- 将再次生成的虚拟 DOM 和就的虚拟 DOM,通过 filber 进行比较,生成 patch 补丁对象
- patch 补丁对象渲染为真实 DOM
- 发送数据请求
- 真实 dom 操作
- 可以获取 getSnapShotBeforeUpdate 传递过来的数据
1 2 3 4 5 6 7 8 9
| componentDidUpdate(prevProps: P, prevState: S, snapShot: number) {
console.log("我得到了", snapShot); }
|
PureComponent vs Component
在 component 中如果渲染一样的值,都会触发 render()钩子函数,导致性能浪费
- PureComponent 默认会进行一次新旧 state 或者新旧 props 的对比,可以得到一个性能优化的目的
- 缺点:
- 它只能对比一层数据,所以我给了它一个专业词 浅比较
- 总结
- PureComponent 会自动进行一次浅比较
- Component 不会自动进行比较的,需要我们手动在 shouldComponentUpdate 中比较
forceUpdate
- 强制渲染,会跳过 shouldComponentUpdate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import React, { Component } from "react";
export default class App extends Component { name = "fox";
setName = () => { this.name = "dog";
this.forceUpdate(); }; render() { return ( <div> <button onClick={this.setName}>修改</button> <p>{this.name}</p> </div> ); } }
|
销毁阶段
- componentWillUnmount
- 触发条件: 组件被销毁了
- 作用
- 清除计时器、定时器
- 清除绑定在 window/document 身上的事件
- 清除第三方实例
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
| import React, { Component } from "react"; import _ from "lodash"; export default class Hello extends Component { timer: any = null; lodash: any = null;
componentDidMount() { this.lodash = _; this.timer = setInterval(() => { console.log("hello", this.lodash); }, 1000); window.onresize = function () { console.log("浏览器尺寸发生了改变"); }; }
componentWillUnmount() { console.log("销毁了"); clearInterval(this.timer); window.onresize = null; delete this.lodash; }
render() { return <div>hello</div>; } }
|
错误处理阶段
- componentDidCatch
- 做什么的
- 写在哪里的?
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
| import React, { Component } from "react"; import Hello from "./Hello";
interface P {}
interface S { errorFlag: boolean; }
export default class App extends Component<P, S> { constructor(props: P) { super(props); this.state = { errorFlag: false, }; }
componentDidCatch(error: any, info: any) { console.log("触发"); if (error) { this.setState({ errorFlag: true, }); } }
render() { if (this.state.errorFlag) return <div> 回退UI</div>; return ( <div> <Hello /> </div> ); } }
|
子组件在 componentDidMount 扔出一个错误
16 版本
- 挂载阶段
- componentWillMount[17 版本弃用了它,用了 static getDerivedStateFromProps]
- 更新阶段
- componentWillReceiveProps 因为 shouldComponentUpdate 也可以监听
- componentWillUpdate 因为造成异步滥用
15 版本
- 通过 React.createClass 来定义类组件的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import React from "react";
export default React.createClass({ getDefaultProps() { return { coloe: "黄皮肤", }; }, getInitailState() { return { count: 1, }; }, });
|
react 受控组件 & 非受控组件 & 半受控组件
受控组件 【表单元素】
- 表单元素的 value 受组件的 state 的控制,这个表单元素我们就称之为受控组件
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
| import React, { Component } from "react";
interface P {}
interface S { val: string; }
export default class App extends Component<P, S> { constructor(props: P) { super(props); this.state = { val: "", }; }
setVal = (e: any) => { this.setState({ val: e.target.value, }); }; render() { const { val } = this.state; return ( <div> <input type="text" value={val} onChange={this.setVal} /> </div> ); } }
|
非受控组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import React, { Component } from "react";
export default class App extends Component { render() { return ( <div> 表单元素自己管理自己的state <hr /> 我们可以认为input的value就是它自己的state <hr /> 表单元素自己管理自己的state,我们称这个表单为 非受控组件 <hr /> {} <input defaultValue="hello" /> </div> ); } }
|
半受控组件
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
| import React, { Component } from "react"; interface P {} interface S { initVal: string; } export default class App extends Component<P, S> { constructor(props: P) { super(props);
this.state = { initVal: "hello", }; }
render() { return ( <div> 表单元素的初始值是由组件来管理的 <hr /> 表单元素value的变化还是交给了表单元素自己管理 <hr /> 这种类型我们称之为 半受控组件 <hr /> <input defaultValue={this.state.initVal} /> </div> ); } }
|