告别 Class 组件:拥抱 React Hooks 带来的函数式新范式

在React的世界里,曾经有一段时间,Class(类)组件是构建动态、有状态应用的不二法门。它们强大、可靠,支撑起了无数复杂的界面。然而,随着应用逻辑的日益复杂,开发者们也逐渐感受到了类组件带来的一些困扰。

小希就是这样一位开发者,她正在维护一个几年前用React构建的项目。她发现,仅仅是一个简单的功能,逻辑就可能散落在componentDidMountcomponentDidUpdatecomponentWillUnmount等多个生命周期方法中。更让她头疼的是,组件内部this的指向问题,总是在不经意间导致bug。她感觉自己不像在写功能,更像是在"驯服"一个难以捉摸的类。

纠缠的逻辑:一个典型的Class组件

让我们看看小希遇到的一个典型场景:一个组件需要根据传入的用户ID,订阅该用户的在线状态,并在组件销毁时取消订阅。

用Class组件实现,代码看起来是这样的:

javascript 复制代码
class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

  render() {
    if (this.state.isOnline === null) {
      return 'Loading...';
    }
    return this.state.isOnline ? 'Online' : 'Offline';
  }
}

问题显而易见:订阅取消订阅 这两个紧密相关的逻辑,被人为地拆分到了componentDidMountcomponentWillUnmount两个完全不同的方法里。当组件逻辑变得更复杂时,这种"分裂"会愈发严重,导致代码难以理解和维护。

豁然开朗:useStateuseEffect 的登场

就在小希为此感到困惑时,她发现了React Hooks。这是一种全新的理念,它允许开发者在不编写类的情况下使用state以及其它React特性。其中,最核心的两个Hooks就是useStateuseEffect

useState:让函数拥有状态

useState彻底告别了this.statethis.setState。它让函数组件可以直接拥有自己的状态。

javascript 复制代码
import React, { useState } from 'react';

function Counter() {
  // 声明一个名为 count 的 state 变量,初始值为 0
  const [count, setCount] = useState(0);

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

代码变得无比直观,状态的声明和更新都在一处,不再需要关心this

useEffect:处理"副作用"的瑞士军刀

useEffect则更具革命性,它统一了过去分散的生命周期概念。数据获取、设置订阅、以及手动更改DOM等操作,都被视为"副作用"(Side Effects),由useEffect来处理。

现在,让我们用Hooks来重写小希的那个状态订阅组件:

javascript 复制代码
import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

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

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    
    // 这个 return 的函数就是"清理"函数
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  }); // 每次渲染后都会执行effect

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

奇迹发生了!订阅取消订阅 的逻辑,现在被完美地组织在了一个useEffect内部。useEffect返回的那个函数,React会在组件销毁时自动执行它,用于"清理"副作用。所有相关的代码都待在了它们应该在的地方,逻辑变得清晰、自洽。这种代码组织方式,让一切都变得井井有条。

终极魔法:封装逻辑的自定义Hook

Hooks真正的威力在于它的可组合性。开发者可以将组件中一些相关的、可复用的状态逻辑,抽离成一个独立的"自定义Hook"(Custom Hook)。自定义Hook本质上只是一个函数,但它的名字必须以use开头。

小希可以将刚才的状态订阅逻辑,封装成一个useFriendStatus的自定义Hook:

javascript 复制代码
import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

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

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

有了这个自定义Hook,原来的组件就可以被简化成这样:

javascript 复制代码
function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

组件本身不再关心订阅的内部实现,它只负责使用useFriendStatus这个Hook来获取状态并渲染UI。逻辑被完美地解耦和复用。想要深入了解更多Hooks的用法,官方文档是最好的起点。

React官方文档:https://react.dev/

结语:一种全新的思考方式

从Class组件到Hooks,这不仅仅是API的改变,更是一种编程思想的转变。它引导开发者用函数式、组合式的方式去思考和组织UI逻辑,而不是陷入复杂的继承和生命周期管理中。

对于像小希这样的开发者来说,Hooks就像一扇窗,让她看到了一个更简洁、更清晰的React世界。如今,Hooks已经成为React社区的主流和未来,无论是开始一个新项目,还是维护旧项目,它都是值得拥抱的新范式。

许多优秀的UI库也早已全面拥抱Hooks。

MUI (原Material-UI)官网:https://mui.com/

相关推荐
十二春秋2 小时前
场景模拟:基础路由配置
前端
六月的可乐2 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程
一 乐3 小时前
智慧党建|党务学习|基于SprinBoot+vue的智慧党建学习平台(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·学习
BBB努力学习程序设计3 小时前
CSS Sprite技术:用“雪碧图”提升网站性能的魔法
前端·html
Zyx20073 小时前
深拷贝:JavaScript 中对象复制的终极解法
javascript
BBB努力学习程序设计3 小时前
CSS3渐变:用代码描绘色彩的流动之美
前端·html
冰暮流星4 小时前
css之动画
前端·css
jump6804 小时前
axios
前端
spionbo4 小时前
前端解构赋值避坑指南基础到高阶深度解析技巧
前端