自言自语
我想大部分人现在学react都会直接上手hook开发,因为很简单,上手比较容易,而且目前业界也都转向hook开发了。但从我学react到现在其实还没有认真思考学习过,react团队为啥会出一个hook,它的优势是什么?什么情况下应该使用类组件?
处理生命周期
在class组件中,处理组件的state需要使用比较多的生命周期钩子,比如componentDidUpdate、shouldComponentUpdate、componentDidMount、componentWillUnMount等等,你要在每个函数中去处理逻辑,相当的麻烦,而且处理state更新的时候还要注意引用类型地址的问题。比如
class ComponentA extends React.Component {
componentDidUpdate(prevProps: Props) {
if (prevProps.obj !== this.props.obj) {
// do something
// 这个过程是一定会执行,因为引用类型地址没变
// 处理的方式一般是用loadsh的isEqual去处理,但这很容易漏,造成组件性能问题甚至性能问题
}
}
render() {
return (
<div>
ComponentA
</div>
)
}
}
相反,用hook的话就使用useState和useEffect这两个hook就可以完成很多事了,大大简化了代码的书写。
编写代码的问题
在类组件中会存在this丢失的情况,但这种倒不是框架的设计问题,js本身有这个问题,所以在类型组件中药使用函数,得使用bind绑定函数或者使用剪头函数,也挺麻烦的
class ComponentA extends React.Component {
logMessage() {
console.log('log message from ComponentA');
}
logMessageA = () => {
console.log('log messageA from ComponentA');
}
render() {
return (
<div onClick={this.logMessage.bind(this)}>
ComponentA
</div>
<div onClick={this.logMessageA}>
</div>
)
}
}
这方面函数式+hook的形式就不需要考虑这么多,不过在useEffect的依赖项中增加对象依旧不是一个优雅的选择。
代码复用的问题
在前端开发中经常会遇到要开发高复用组件的场景,需要用到高阶组件,而class组件在使用高阶组件的过程中会有组件嵌套的问题,逻辑更加复杂,容易形成屎山。
这里的实例只用到了一个logger,但是现实开发中,需求是在叠加的,
class组件
const useLogger = (Component) => {
class LoggerComponent extends React.Component {
componentDidMount() {
console.log('component dit mount');
}
componentWillUnMount() {
console.log('component will un mount');
}
render() {
return <Component {...this.props}/>;
}
}
return LoggerComponent;
}
class DemoComponent extends React.Component {
render() {
return <div>demo></div>
}
}
const loggerComponent = useLogger(DemoComponent);
hook
import { useEffect } from 'react';
const useLogger = () => {
useEffect(() => {
console.log('component dit mount');
return () => {
console.log('component will un mount');
};
}, []);
};
function MyDemoComponent() {
useLogger();
return <div>demo</div>;
}
需要用到类组件的场景
正常的前端ui界面搭建,我想直接用hook就够了,不过在一些特殊的开发场景,类的优势会体现出来。比如你正常做一个绘图的web端软件。
你需要提供很多种绘画的方式,比如曲线、直线、圆圈、文字等,这些通常用canvas做,涉及到3d的用webgl底层做。在做这部分设计类的软件的时候,你需要一个类似tool的组件。
classDiagram
DrawTool <|-- DrawStraightLineTool
DrawTool <|-- DrawCurveTool
class DrawTool {
type: ToolType.DrawStraightLine;
DrawType: drawType;
draw();
stop();
beforeLeaveTool();
afterLeaveTool();
active();
}
class DrawStraightLineTool {
drawType: DrawType.Straight;
draw();
stop();
....()
}
class DrawCurveTool {
drawType: DrawType.Curve;
draw();
stop();
....()
}
在这个例子里你需要有一个基类DrawTool和两个子类DrawStraightLineTool和DrawCurveTool,通过多态的方式来实现绘制过程中的一些交互。在这个场景下,class组件就能发挥它的优势了,这种工具类的架构,class组件确实比函数式要来的方便,不过对于维护代码的人的要求要更高点。