为什么需要hooks实现声明周期
函数组件本身是无状态的,因此如果想要像类组件一样使用生命周期等特性,需要接入hook来实现,那么hooks如何实现类组件中的生命周期呢?
具体生命周期
- 类组件中的constructor构造函数 ⇒ useState()。类组件中,构造函数会在实例化时为组件初始化状态;函数组件第一次使用useState()时可以记录state到fiber实现状态初始化。
class Example extends Component {
constructor() {
super();
this.state = {
data: 0
}
}
render() {
return <div></div>;
}
}
function Example() {
const [data, setData] = useState(0);
return <div></div>;
}
- componentDidMount ⇒ useEffect(() ⇒ {}, [])。传给 useEffect 的函数会在浏览器完成布局与绘制之后(不会阻塞渲染) ,在一个延迟事件中被调用。函数组件的useEffect在不提供依赖时表示只运行一次的 effect(仅在组件挂载和卸载时执行)。
class Example extends Component {
componentDidMount() {
console.log('mounted');
}
render() {
return <div></div>;
}
}
function Example() {
useState(() => {
console.log('mounted');
}, []);
return <div></div>;
}
- shouldComponentUpdate ⇒ React.memo()。shouldComponentUpdate能够对比props和state的变化;React.memo()可以对比props,而函数组件中还可以利用useMemo来缓存state。
React.memo()只是浅比较props,如果函数组件中存在useState、useReducer、useContext,当state或context变化时依然还会重新渲染。
class Example extends Component {
shouldComponentUpdate() {
console.log('shouldComponentUpdate');
}
render() {
return <div></div>;
}
}
function _Example() {
useState(() => {
console.log('mounted');
}, []);
return <div></div>;
}
const Example = React.memo(
_Example,
(prevProps, nextProps) => nextProps.count !== prevProps.count
)
- componentDidUpdate ⇒ useEffect(() ⇒ {}) + useRef。useEffect没有指定第二个依赖项的参数时,会在每次渲染结束后执行,虽然模拟了componentDidUpdate,但是也在componentDidMount时触发了,因此借用useRef来记录是否进行过第一次渲染。
class Example extends Component {
**componentDidUpdate**() {
console.log('**componentDidUpdate'**);
}
render() {
return <div></div>;
}
}
function Example() {
const didMount = useRef(false);
useEffect(() => {
if(didMount.current) {
console.log('**componentDidUpdate');**
} else {
console.log('**componentDidMount');
didMount.current = true;**
}
****});
return <div></div>;
}
- componentWillUnmount ⇒ useEffect(() ⇒ {}, [])。通过为useEffect中return卸载函数,可以指定组件卸载时的操作。
class Example extends Component {
componentWillUnmount() {
console.log('componentWillUnmount**'**);
}
render() {
return <div></div>;
}
}
function Example() {
const didMount = useRef(false);
useEffect(() => {
return () => {
console.log('componentWillUnmount');
}
****}, []);
return <div></div>;
}
- getDerivedStateFromProps ⇒ 函数组件“render”过程中重新设定state。重新设定state会使 React 立即退出第一次渲染并用更新后的 state 重新运行组件以避免耗费太多性能。
getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
function ScrollView({row}) {
const [isScrollingDown, setIsScrollingDown] = useState(false);
const [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// Row 自上次渲染以来发生过改变。更新 isScrollingDown。
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
参考
- 生命周期方法要如何对应到 Hook?: zh-hans.reactjs.org/docs/hooks-…