分享个人 Full-Stack JavaScript 项目开发经验
了解 React 类组件生命周期的使用方式,对组件构建、性能优化和避免副作用十分重要。下面依据 16 版本的 React 和紧跟其 17 版本,整理以下生命周期说明。
import PropTypes from "prop-types";
class Example extends React.Component {
constructor(props) {
// 必须在使用 this 关键字之前使用,传入参数 props 调用父类的构造函数。
super(props);
// 可以在这里基于 props 来初始化 state,但 state 不会随 props 更新而更新。
this.state = {
color: props.initialText
};
}
handleChange = () => {
// 该语法为属性初始化器语法的箭头函数,this 被绑定到组件类
this.setState((prevState, props) => stateChange, [callback]);
// 注意:setState() 是异步的,其可能是批处理或推迟更新。
// 所以基于渲染之后执行的操作,应该在参数二的回调函数中或者 componentDidUpdate 生命周期函数中完成。
// stateChange 将会浅合并到新状态中,它也可以直接以对象形式给出。
}
handleModelChange() {
// 当组件依赖的外部数据发生改变,可以使用 forceUpdate()。
// 它会忽略该组件的 shouldComponentUpdate(),导致 render() 方法被调用。
// 它也将会触发每个子组件的生命周期方法。
this.forceUpdate();
// 通常情况,应该尽量避免使用它,组件仅从 this.props 和 this.state 中读取数据
}
static getDerivedStateFromProps(nextProps, prevState) {
// 组件实例化后,接受新 props 时会调用。
// 该方法意思是从新 props 中获得衍生 state。
// 返回 null 表明不需要更新任何状态。
// 返回对象将用于更新新状态。
// 它也是 componentWillReceiveProps 的替代方法。
// 示例:
// if (nextProps.userID !== prevState.prevPropsUserID) {
// return {
// prevPropsUserID: nextProps.userID,
// email: nextProps.defaultEmail
// };
// }
// return null;
}
componentDidMount() {
// 组件装配到 DOM 后立即调用
// 在这生命周期函数你可以:
// 获取 DOM 尺寸或位置等、
// 发送网络请求,从远端加载数据、
// 实例化第三方库等。
// 包含了调用者定义的属性。
this.props
// 这个特定属性表示组件的开始和结束标记之间的内容。
this.props.children
// 表示组件的特定数据的 JavaSript 对象。
// 若该特定数据不需要在 render() 中使用,可以直接放在实例中,如 this.myData。
// 应该把 state 作为不可变数据,仅使用 setState() 替换你之前做的改变。
this.state
}
componentWillUnmount() {
// 组件被卸载和销毁之前立刻调用。
// 在该方法里处理必要的清理工作,如:
// 解绑定时器、
// 解绑事件处理函数、
// 取消网络请求、
// 销毁第三方库实例、
// 清理任何在 componentDidMount 环节创建的 DOM 元素等。
}
shouldComponentUpdate(nextProps, nextState) {
// 当接收到新 props (可能来自父组件)或状态时,其在渲染前被调用,默认返回 true。
// 返回 false 则 UNSAFE_componentWillUpdate()、render() 和 componentDidUpdate() 将不会被调用。
// 注意:初始化渲染和使用 forceUpdate() 时候不会调用这方法。
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 在最新的渲染输出提交给 DOM 前将会立即调用。
// 该方法可以用于在组件值(包括对应 DOM 的参数,可通过 ref 获得)改变前获取它们,函数返回值将会作为参数传递给 componentDidUpdate(prevProps, prevState, snapshot)。
// 注意:由于异步渲染,componentWillUpdate 在“渲染”时期,getSnapshotBeforeUpdate 在“提交时期”,componentWillUpdate 读取 DOM 参数将会是滞后的。
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 更新发生后立即被调用。
// 该方法并不会在初始化渲染时调用。
// 若 shouldComponentUpdate() 返回false,其将不会被调用。
// 在这方法中可能做的操作:
// 操作更新后的 DOM、
// 对比新旧 props 和 state 后发送网络请求。
}
UNSAFE_componentWillMount() {
// 装配发生前被调用(旧名称为 componentWillMount)。
// 方法里设置状态不会触发重渲。
// 注意:该方法推荐使用 constructor() 代替。
}
UNSAFE_componentWillReceiveProps(nextProps) {
// 装配后的组件接收到新 props 时调用(旧名称为 componentWillReceiveProps)。
// 该方法一般用于根据 this.props 和 nextProps,使用 this.setState() 设置新状态。
// 注意:该方法推荐使用 static getDerivedStateFromProps() 代替。
}
UNSAFE_componentWillUpdate() {
// 接收到新 props 或 state 后,渲染前调用(旧名称为 componentWillUpdate)。
// 该方法不会在初始化渲染前调用。
// 若 shouldComponentUpdate() 返回false,其将不会被调用。
// 注意:不能在这里调用 this.setState(),很可能会造成死循环。
// 需要更新状态时应在 static getDerivedStateFromProps(nextProps, prevState) 中完成。
}
componentDidCatch(error, info) {
// 定义该生命周期方法,则该类组件将成为一个错位边界组件。
// error 是被抛出的错误。
// info 是一个含有 componentStack 属性的对象。这一属性包含了错误期间关于组件的堆栈信息。
// 错误边界捕捉发生在它们子组件渲染期间、生命周期方法中和构造函数中的错误,但不能捕捉自己内部的错误。
// 事件处理器使用普通的 try/catch 即可。
// 提示:
// render() {
// if (this.state.hasError) {
// // You can render any custom fallback UI
// return <h1>Something went wrong.</h1>;
// }
// return this.props.children;
// }
// 注意:错误边界只用捕获 JavaScript 错误,记录这些错误,并显示回退 UI,不能用于控制流。
}
render() {
// 在此检查 this.props 和 this.state,并返回以下类型之一:
// React 元素
// 字符串/数字
// ReactDOM.createPortal
// null / boolean (什么都不渲染)
// 注意:render() 应该是纯净的,不改变组件状态,直接和浏览器交互
// 提示:可以通过使用一个数组让 render() 返回多个元素(添加 key)
}
}
// 对于组件中 undefined 的 props 会从这类属性中获取默认值
// 注意:当 props 被设置为 null 时,该属性无效
Example.defaultProps = {};
// props 类型检查,发生在 defaultProps 赋值之后
// 这有助于定位 bug
Example.propTypes = {
initialText: PropTypes.string
};
// 导出组件对象
export {Example};