这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战
首先对比一下以往的函数式组件和类式组件的不同。
类式组件 | 函数式组件 |
---|---|
需要继承 | 不需要 |
有生命周期方法 | 不可以 |
可以定义且维护state | 不可以 |
可以获取到实例的this,而且可以根据this去做事 | 不可以 |
... | ... |
类式组件
先来看看类式组件
class DemoClass extends React.Component {
// 初始化类组件的 state
state = {
text: ""
};
// 编写生命周期方法 didMount
componentDidMount() {
// 省略业务逻辑
}
// 编写自定义的实例方法
changeText = (newText) => {
// 更新 state
this.setState({
text: newText
});
};
// 编写生命周期方法 render
render() {
return (
<div className="demoClass">
<p>{this.state.text}</p>
<button onClick={this.changeText}>点我修改</button>
</div>
);
}
}
类式组件中有state,生命周期,像是一个全副武装的战舰,但是大的同时也让你的学习成本变得很高,而且复杂的同时难以拆解和复用,可能你需要学习高阶组件,RenderProps,用更高的成本来交换编码的灵活度。
函数式组件
相比较于类式组件,函数式组件更像式一艘快艇。
function DemoFunction(props) {
const { text } = props
return (
<div className="demoFunction">
<p>{`function 组件所接收到的来自外界的文本内容是:[${text}]`}</p>
</div>
);
同时他们之间有一个核心的差别
就是函数式组件可以捕获render内部的状态,这是两种组件最大的不同。
而且从思想上说,是面向对象和函数式编程的两种思想的差异。
函数式组件更契合React框架的设计理念。
React本身的定位就像是一个吃进数据,吐出UI的函数。因此,React需要将数据和渲染紧紧的绑定到一起,让数据去驱动渲染,也就是state => view,而类组件是做不到这一点的。
以Dan的demo为例子。文章地址
class ProfilePage extends React.Component {
showMessage = () => {
alert('Followed ' + this.props.user);
};
handleClick = () => {
setTimeout(this.showMessage, 3000);
};
render() {
return <button onClick={this.handleClick}>Follow</button>;
}
}
这个组件的意思就是当你点击Follow的时候在三秒后输出当前你关注的这个人,也就是代码中对应的this.props.user。但是类式组件有一个问题,那就是假如你在点击这个按钮后的三秒内将传入的props改变,那么最后弹出的就不是Dan,而是Sophie。
类组件上的props是不可变的,但是this是可变的,this的数据可以修改。this.props调用时会获取最新的props,这是React保证数据实时性的手段。多数情况下,this.props和this.state的变化能够和预期中的渲染动作保持一致。但是在这个demo中,用setTimeout将渲染推迟了3s,打破这之中的关联,因此导致渲染时捕获到的不是我们想要的结果。
这同样也代表类式组件并没有把state和渲染紧紧绑定在一起。
而如果改造成函数式组件呢?
function ProfilePage(props) {
const showMessage = () => {
alert('Followed ' + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
<button onClick={handleClick}>Follow</button>
);
}
此时我们可以确保任何时机下获取的props都是触发函数时的那个props,这样我们保证了渲染结果符合预期。也就是说函数式组件真正的把数据和渲染绑定到了一起。