Function Component 和 Class Component 区别
语法
- functional component语法更简单,只需要传入一个props参数,返回一个react片段。
- class component 要求先继承React.Component然后增加一个render方法,在render里面返回react片段
有无state状态
- 因为function component 只是一个普通的函数所以不可以在其中用this.state , setState(),这也是它被叫做无状态组件的原因。
- 一个组件需要用到状态的时候要用到class component。
声明周期
- function component 不具有生命周期,因为所有的生命周期钩子函数均来自于React.Component。
- 所以当一个组件需要生命周期钩子的时候我们也需要class component
各自优势
-
Function Component因为没有状态,可以只负责表现层的逻辑。不用考虑因为复杂的逻辑去改变状态,这样有利于代码复用。
-
Class Component 。当需要实现一些容器组件的时候,需要改变内部状态;当需要用到生命周期钩子函数实现一些功能的时候;在组件内部用shouldComponentUpdate 方法来去判断,减少组件渲染次数,可以提升性能。
但是有了React Hooks之后,Function Component配合上Hooks就很强大了。
为什么不用class component,要用Hooks?
想要复用一个有状态的class组件过于麻烦
class组件本身包含了状态,难以复用。
有了hooks,不需要写class,所有的组件都是function。Hooks允许您在不更改组件层次结构的情况下复用有状态的逻辑。这样可以轻松的在许多组件之间共享Hooks。
代替生命周期
生命周期钩子函数里的逻辑混。比如我们需要在componentDidMount中发起ajax请求获取数据,绑定一些事件监听等,有时候我们还需要在componentDidUpdate做一遍同样的事情,这样代码很不直观。使用Hooks用一条useEffect可以直接做到componentDidMount+componentDidUpdate,而且很直观。
class内的this指向让人困惑
使用class创建组件时,要时刻注意this的指向。一旦忘了绑定this,会有各种bug。使用Hooks就不需要面对this,比如 const [count, setCount] = useState(0); 里面的count只是一个变量,可以直接用了,不需要 this.state.count。
使用React Hooks模拟生命周期
constructor
React Hooks基于函数组件,不需要构造函数。可以通过调用useState初始化state
const [count, setCount] = useState(0);
componentDidMount
把useEffect第二个参数设为空数组 [],这样的话回调函数只会在首次渲染之后执行一次,类似于componentDidMount
useEffect(() => {
document.title = `You clicked ${count} times`;
}, []);
可以给useEffect传第二个参数,另这个数组存在并有值,只有当渲染后数组中的任何值发生更改,才会执行回调。
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); //只有当count的值发生变化时,才执行副作用函数
componentDidUpdate
如果useEffect的第二个参数不存在首次渲染和之后的每次渲染都会调用回调函数,相当componentDidMount+componentDidUpdate
useEffect(() => {
document.title = `You clicked ${count} times`;
});
componentWillUnmount
在useEffect的回调函数中返回一个函数,我们可以在这里面清除定时器或事件监听器,或者解除订阅。
下面这种情况,这个函数会在组件卸载前被调用,相当于componentWillUnmount
useEffect(() => {
return () => {
console.log('Will Unmount');
};
}, []);
下面这种情况是一个发布订阅模式,让我们传给useEffect的副作用函数返回一个新的函数,这个新的函数将会在组件下一次重新渲染之后执行
import { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// 一定注意下这个顺序:告诉react在下次重新渲染组件之后,同时是下次调用ChatAPI.subscribeToFriendStatus之前执行cleanup
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
代码执行顺序是这样的
1.页面首次渲染
2.替friend.id=1的朋友注册
3.突然friend.id变成了2
4.页面重新渲染
5.清除friend.id=1的绑定
6.替friend.id=2的朋友注册
...
第一次渲染,注册第一个
每次重新渲染,都会清掉之前的,注册最新的
组件卸载前会把最后一个清掉