如何在函数组件中模拟生命周期?

·  阅读 299
如何在函数组件中模拟生命周期?

前言

项目之前已经用了函数组件,后面的需求需要初始化组件的数据,那怎么实现componentDidMount()的效果呢? 答:用useEffect模拟实现。

下面结合官方文档介绍useEffect,以及如何模拟生命周期。(需要直接看结果的,直接拉到最后~~)

注意:只有class组件才有生命周期方法,函数组件是没有的。

Effect Hook

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Effect Hook 可以让你在函数组件中执行副作用操作。

如果对hook不是很理解的可以看看这片文章:轻松学会 React 钩子:以 useEffect() 为例

Hook使用规则

  • 只能在函数最外层调用,不要再循环、条件判断或者子函数中调用。
  • 只能在React的函数组件中调用Hook

示例

import React, { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {    document.title = `You clicked ${count} times`;  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
复制代码

上面例子可以看出useEffect是怎样使用的。通过useEffect可以告诉React组件需要在渲染后执行某些操作。React会保存你传递的effect,并且在执行DOM更新之后调用它。而将useEffect放在组件内部让我们可以在effect中直接访问state变量,不需要特殊的API来读取它(已经保存在函数作用域中)。 默认情况下,useEffect在第一次渲染之后每次更新之后都会执行。

useEffect 可以在组件渲染后实现各种不同的副作用。与 componentDidMount 或 componentDidUpdate 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。大多数情况下,effect 不需要同步地执行。

可清除的Effect

只需在effect 返回一个函数,React 将会在执行清除操作时调用它

useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
复制代码

在effect 返回一个函数,是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。React 会在组件卸载的时候执行清除操作。

注: React 会在执行当前 effect 之前对上一个 effect 进行清除。每次更新的时候都要运行 Effect,可以避免在 class 组件中因为没有处理更新逻辑而导致常见的 bug

useEffect 的第二个参数

是可以选参数,通过传入数组可以约束useEffect在哪些数据需要更新时执行。(对于有清除操作的 effect 同样适用。)

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
复制代码

模拟生命周期

通过前面的介绍,可以猜到是怎么实现了吧?来张官方文档截图~~~

image.png

  • 示例
useEffect(() => {
  // 相当于 componentDidMount
  document.title = `You clicked ${count} times`;
  
  return () => {
    // 相当于 componentWillUnMount
    ...
  }
}, []); 

useEffect(() => {
  // 相当于 componentDidUpdate
  document.title = `You clicked ${count} times`;
}); 
复制代码
  • 效果

image.png

image.png

分类:
前端
标签: