一、class组件
React 有两种组件:class组件 和 函数组件。class组件需要继承 React.Component,用法如下:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
1、必须要重写的方法
每一个继承 React.Component
的组件,都必须重写 render()
方法。
2、组合而非继承
React建议:不要创建自定义基类组件,使用组合而非继承的方式写组件。
二、组件生命周期
1、方法运行图谱
2、挂载
当组件实例被创建并插入 DOM 中时,调用顺序如下:
- constructor()
-
在组件挂载前被调用,使用方法及注意点如下:
constructor(props) { // 1、一定要写这句,否则会出现 this.props 未定义bug。 super(props); // 2、构造函数是唯一能给state初始化的地方,但不要调用 this.setState() 赋值, // 会触发render()方法,引起不必要的bug。 this.state = { counter: 0 }; // 3、这里可以绑定组件的 事件处理函数 this.handleClick = this.handleClick.bind(this); }
- static getDerivedStateFromProps()
-
功能是:根据 props 的变化来更新 state。
// 初始挂载及后续更新时都会被调用, static getDerivedStateFromProps(props, state)
- render()
- componentDidMount()
- 【调用】:会在组件挂载后(插入 DOM 树中)被调用;
- 【使用】:适合于
数据初始化操作
、网络请求获取数据操作
。 - 【注意】:这里调用 setState(),会触发render(),请谨慎使用,容易导致性能问题。
3、更新
当组件的 props 或 state 发生变化时会触发更新。调用顺序如下:
- static getDerivedStateFromProps()
-
功能是:根据 props 的变化来更新 state。
// 初始挂载及后续更新时都会被调用, static getDerivedStateFromProps(props, state)
- shouldComponentUpdate()
此方法仅用于性能优化。返回true,表示组件需要重新渲染;返回false,表示跳过渲染,默认返回值为 true。
首次渲染或使用 forceUpdate() 时不会调用。
state 或 props 改变时,shouldComponentUpdate() 会在渲染执行之前被调用。
不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。
- render()
- getSnapshotBeforeUpdate()
-
在组件发生更改之前获取一些信息(譬如:滚动位置等),返回值将作为参数传递给 componentDidUpdate()
// 函数原型 getSnapshotBeforeUpdate(prevProps, prevState)
// 使用实例 class ScrollingList extends React.Component { constructor(props) { super(props); this.listRef = React.createRef(); } getSnapshotBeforeUpdate(prevProps, prevState) { // 我们是否在 list 中添加新的 items ? // 捕获滚动位置以便我们稍后调整滚动位置。 if (prevProps.list.length < this.props.list.length) { const list = this.listRef.current; return list.scrollHeight - list.scrollTop; } return null; } componentDidUpdate(prevProps, prevState, snapshot) { // 如果我们 snapshot 有值,说明我们刚刚添加了新的 items, // 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。 //(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值) if (snapshot !== null) { const list = this.listRef.current; list.scrollTop = list.scrollHeight - snapshot; } } render() { return ( <div ref={this.listRef}>{/* ...contents... */}</div> ); } }
- componentDidUpdate()
组件更新后会被调用,首次渲染不会执行此方法。
-
可以执行一些自定义操作,譬如进行一些网络数据请求。
componentDidUpdate(prevProps) { // 典型用法(不要忘记比较 props): if (this.props.userID !== prevProps.userID) { this.fetchData(this.props.userID); } }
可以调用 setState(),但是一定要用条件语句包裹 setState(),否则渲染会进入死循环,因为setState会触发render(),render()后又会调用componentDidUpdate。请谨慎使用。
如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()。
4、卸载
- componentWillUnmount()
- 当组件从 DOM 中移除时(卸载及销毁之前)调用。
- 在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
5、错误处理
当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:
- static getDerivedStateFromError()
-
在渲染阶段,后代组件抛出错误后被调用。
// 函数原型 static getDerivedStateFromError(error)
// 使用示例 class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 更新 state 使下一次渲染显示自定义错误UI return { hasError: true }; } render() { if (this.state.hasError) { // 你可以渲染任何自定义的 UI return <h1>Something went wrong.</h1>; } return this.props.children; } }
- componentDidCatch()
-
// 后代组件抛出错误后被调用,可用于写错误日志
// 函数原型 componentDidCatch(error, info) // error : 抛出的错误; // info : 错误的堆栈信息
// 使用示例 class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 更新 state 使下一次渲染可以显示降级 UI return { hasError: true }; } componentDidCatch(error, info) { // "组件堆栈" 例子: // in ComponentThatThrows (created by App) // in ErrorBoundary (created by App) // in div (created by App) // in App logComponentStackToMyService(info.componentStack); } render() { if (this.state.hasError) { // 你可以渲染任何自定义的降级 UI return <h1>Something went wrong.</h1>; } return this.props.children; } }
6、属性
- defaultProps
-
为 props 添加默认值。
class CustomButton extends React.Component { // ... } CustomButton.defaultProps = { color: 'blue' };
render() { return <CustomButton />; // props.color 将设置为 'blue' }
- displayName
- 字符串类型,多用于调试消息。
- props
- 组件的内置属性,可用于组件间的属性数据传递。
this.props.children
:特指子组件。详细用法,看这里!
- state
- 组件内置属性,它是一个普通 JavaScript 对象,用于组件内表示随时会发生变化的数据。详细用法,看这里!
7、其他
- setState()
-
函数原型
setState(updater, [callback])
-
updater:如下两种使用方式
// 用函数方式: this.setState((state, props) => { return { counter: state.counter + props.step }; }); // 用对象方式: this.setState({ quantity: 2 })
callback参数: 组件更新完成后进行的回调,不建议使用,应该把操作放在 componentDidUpdate() 中更合适。
- forceUpdate()
-
强制调用 render() 进行重新渲染,会跳过 shouldComponentUpdate(),但其子组件会不会跳过。通常应该避免使用此方法。
// 函数原型 component.forceUpdate(callback)