Skip to content

使用 React hooks 怎么实现类里面的所有生命周期?

Posted on:2024年8月10日 at 21:50

在 React 16.8 之前,函数组件也称为无状态组件,因为函数组件也不能访问 react 生命周期,也没有自己的状态。react 自 16.8 开始,引入了 Hooks 概念,使得函数组件中也可以拥有自己的状态,并且可以模拟对应的生命周期。

我们应该在什么时候使用 Hooks 呢?

官方并不建议我们把原有的 class 组件,大规模重构成 Hooks,而是有一个渐进过程:

那么相对于传统class, Hooks 有哪些优势?

class 生命周期在 Hooks 中的实现

Hooks 组件更接近于实现状态同步,而不是响应生命周期事件。但是,由于我们先熟悉的 class 的生命周期,在写代码时,难免会受此影响,那么 Hooks 中如何模拟 class 的中的生命周期呢:

总结:

class 组件Hooks 组件
constructoruseState
getDerivedStateFromPropsuseEffect 手动对比 props, 配合 useState 里面 update 函数
shouldComponentUpdateReact.memo
render函数本身
componentDidMountuseEffect 第二个参数为[]
componentDidUpdateuseEffect 配合useRef
componentWillUnmountuseEffect 里面返回的函数
componentDidCatch
getDerivedStateFromError

代码实现:

import React, { useState, useEffect, useRef, memo } from "react";

// 使用 React.memo 实现类似 shouldComponentUpdate 的优化, React.memo 只对 props 进行浅比较
const UseEffectExample = memo((props) => {
  console.log("===== UseStateExample render=======");
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);
  const [count2, setCount2] = useState(0);
  const [fatherCount, setFatherCount] = useState(props.fatherCount);

  console.log(props);

  // 模拟 getDerivedStateFromProps
  useEffect(() => {
    // props.fatherCount 有更新,才执行对应的修改,没有更新执行另外的逻辑
    if (props.fatherCount == fatherCount) {
      console.log("======= 模拟 getDerivedStateFromProps=======");
      console.log(props.fatherCount, fatherCount);
    } else {
      setFatherCount(props.fatherCount);
      console.log(props.fatherCount, fatherCount);
    }
  });

  // 模拟DidMount
  useEffect(() => {
    console.log("=======只渲染一次(相当于DidMount)=======");
    console.log(count);
  }, []);

  // 模拟DidUpdate
  const mounted = useRef();
  useEffect(() => {
    console.log(mounted);
    if (!mounted.current) {
      mounted.current = true;
    } else {
      console.log("======count 改变时才执行(相当于DidUpdate)=========");
      console.log(count);
    }
  }, [count]);

  // 模拟 Didmount和DidUpdate 、 unmount
  useEffect(() => {
    // 在 componentDidMount,以及 count 更改时 componentDidUpdate 执行的内容
    console.log(
      "======初始化、或者 count 改变时才执行(相当于Didmount和DidUpdate)=========",
    );
    console.log(count);
    return () => {
      console.log("====unmount=======");
      console.log(count);
    };
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>

      <button onClick={() => setCount2(count2 + 1)}>Click me2</button>
    </div>
  );
});

export default UseEffectExample;

注意事项

function FriendStatus(props) {
  // ...
  useEffect(() => {
    // ...
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  // ...
}

// Mount with { friend: { id: 100 } } props
ChatAPI.subscribeToFriendStatus(100, handleStatusChange); // 运行第一个 effect

// Update with { friend: { id: 200 } } props
ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 清除上一个 effect
ChatAPI.subscribeToFriendStatus(200, handleStatusChange); // 运行下一个 effect

// Update with { friend: { id: 300 } } props
ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 清除上一个 effect
ChatAPI.subscribeToFriendStatus(300, handleStatusChange); // 运行下一个 effect

// Unmount
ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一个 effect
原文转自:https://fe.ecool.fun/topic/460a9714-1001-4beb-b12a-be8fec732879