相比于 class 组件,hooks到底解决了什么问题?

2024-04-24 15:52

本文主要是介绍相比于 class 组件,hooks到底解决了什么问题?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面

相信使用 react 的小伙伴,都使用过 Class 组件和函数式组件。

目前来说,函数式组件比较流行,基本上新开发的项目都是以函数式组件为主。

那相比于这两种方式,最直观的就是函数式组件引入了 hooks,在引入 hooks 之后函数式组件变得更加灵活,所以这个问题基本上就是考察你对两种组件的理解,今天就以我个人的理解给大家分享一下,希望可以帮助到大家!

1、状态逻辑复用

class 组件中状态逻辑难以复用,常常需要使用高阶组件或 Render Props。

hooks 引入了 useState、useReducer 等钩子,使得状态逻辑可以更容易地在不同组件之间共享和复用。

下面我们来举个栗子看看:

假设我们有两个组件 Counter1 和 Counter2,它们都需要使用 count 状态和 increment 函数。

类组件:

在这个例子中,两个组件有相同的状态逻辑,但由于类组件的特性,我们无法很好地抽象出这些逻辑进行复用。

class Counter1 extends React.Component {state = { count: 0 };increment = () => {this.setState(prevState => ({ count: prevState.count + 1 }));};render() {return (<div><p>Counter 1: {this.state.count}</p><button onClick={this.increment}>Increment</button></div>);}
}class Counter2 extends React.Component {state = { count: 0 };increment = () => {this.setState(prevState => ({ count: prevState.count + 1 }));};render() {return (<div><p>Counter 2: {this.state.count}</p><button onClick={this.increment}>Increment</button></div>);}
}

使用hooks:

使用 hooks,我们可以将这些逻辑抽象为一个自定义 hook,这样在Counter1 和 Counter2中可以复用一个函数,而不需要重写多个相同的逻辑。

import { useState } from 'react';function useCounter() {const [count, setCount] = useState(0);const increment = () => setCount(prevCount => prevCount + 1);return { count, increment };
}function Counter1() {const { count, increment } = useCounter();return (<div><p>Counter 1: {count}</p><button onClick={increment}>Increment</button></div>);
}function Counter2() {const { count, increment } = useCounter();return (<div><p>Counter 2: {count}</p><button onClick={increment}>Increment</button></div>);
}

2、生命周期管理

class 组件中的生命周期方法(如 componentDidMount、componentDidUpdate 等)往往包含多个不相关的逻辑,导致代码不够清晰。hooks 提供了 useEffect 钩子,根据依赖项的不同情况可以模拟这几个声明周期函数,也就是一个 hooks 可以实现多个声明周期。

1.模拟 componentDidMount

componentDidMount():在组件被挂载到 DOM 后调用,通常用于发送网络请求、订阅事件等初始化操作。

使用useEffect:依赖项为空数组,初次渲染执行

  useEffect(() => {console.log('Component mounted');// 执行数据获取操作fetchData();}, []);

2.模拟 componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot):在组件更新后调用,通常用于处理更新后的操作,比如更新 DOM 或进行网络请求。

使用useEffect:依赖项为state,state变化时执行

  useEffect(() => {console.log('Component updated');// 执行其他副作用操作document.title = `You clicked ${count} times`;}, [count]);

3.模拟 componentWillUnmount

componentWillUnmount():在组件即将从 DOM 中移除时调用,用于清理工作,比如取消订阅、清除定时器等。

使用useEffect:在组件卸载时执行return,清理副作用

  useEffect(() => {return () => {console.log('Component unmounted');// 执行清理操作clearSubscription();};}, []);

3、性能优化

hooks 可以帮助避免不必要的组件重新渲染,通过 useMemouseCallback 等钩子进行性能优化。

 useMemo

用于记忆(缓存)计算结果,并在依赖项变化时重新计算。 这有助于避免不必要的重复计算,提高性能。 

    import React, { useMemo } from 'react';function ExpensiveComponent({ prop1, prop2 }) {// 使用 useMemo 缓存计算结果const result = useMemo(() => {// 进行昂贵的计算或处理return prop1 + prop2;}, [prop1, prop2]); // 依赖项数组return <p>Result: {result}</p>;}

useCallback

用于缓存回调函数,避免在每次渲染时重新创建。

接收一个回调函数和依赖项数组,返回缓存后的回调函数。

useCallback的依赖项参数用于指定哪些变量的变化会导致生成新的回调函数。

   import React, { useState, useCallback } from 'react';function MemoizedComponent() {const [count, setCount] = useState(0);const handleClick = useCallback(() => {// 使用 count 进行逻辑处理console.log(count);}, [count]);return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button><ChildComponent onClick={handleClick} /></div>);}function ChildComponent({ onClick }) {// 使用缓存后的回调函数return <button onClick={onClick}>Click me</button>;}

在这个例子中,useCallback 缓存了 handleClick 回调函数,并且指定了依赖项数组为[count]。这意味着只有当 count 发生变化时,handleClick 才会生成新的回调函数。 

总结

hooks 的出现 让 React 函数组件也能够更好的进行状态复用以及使用 useEffect 模拟生命周期的实现,还提高了代码的可读性、复用性和可维护性。

这篇关于相比于 class 组件,hooks到底解决了什么问题?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/932171

相关文章

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

全面解析MySQL索引长度限制问题与解决方案

《全面解析MySQL索引长度限制问题与解决方案》MySQL对索引长度设限是为了保持高效的数据检索性能,这个限制不是MySQL的缺陷,而是数据库设计中的权衡结果,下面我们就来看看如何解决这一问题吧... 目录引言:为什么会有索引键长度问题?一、问题根源深度解析mysql索引长度限制原理实际场景示例二、五大解决

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题

《解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题》:本文主要介绍解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4... 目录未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘打开pom.XM

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复