React 函数组件开发必备:十大常用 Hooks 使用指南

一、回顾一下Hooks的概念

Hooks 是 React 16.8 版本引入的新特性,它可以让你在函数组件中使用 state 以及其他 React 特性。在此之前,只有 class 组件才能使用这些功能。Hooks 的引入,使得我们可以在不使用类的情况下构建 React 应用程序。

二、 Hooks 解决了什么问题

  1. 组件复用状态逻辑的问题
    之前,我们通常会在生命周期函数中编写代码逻辑,而生命周期函数难以进行复用。Hooks 则可以把这些逻辑抽离到一个可复用的函数中。

  2. 大型组件难以理解
    React 组件越来越大,代码逻辑就会变得难以理解和维护。Hooks 通过将相关逻辑分割到更小的函数中,使代码更加清晰易懂。

  3. 难以理解的 class
    对于一些开发人员来说,在 JavaScript 中理解 class 并不是一件容易的事情。Hooks 完全使用函数,让开发人员更容易理解React组件。

三、常见的Hooks有哪些

  • useState:用于声明状态变量
  • useEffect:用于处理组件的副作用
  • useContext:用于订阅 React 上下文
  • useReducer:用于管理组件状态
  • useCallback:用于缓存函数
  • useMemo:用于缓存计算结果
  • useRef:用于创建可变的 ref 对象
  • useImperativeHandle:用于自定义暴露给父组件的实例值
  • useLayoutEffect:与 useEffect 相同,但是会在所有DOM改变之后同步触发
  • useDebugValue:用于在 React 开发工具中显示自定义 hook 的标签

总的来说,Hooks 让我们在函数组件中也能使用 state 以及其他 React 特性,提高了组件逻辑复用性,同时使代码更加清晰易懂。

四、10种核心Hooks用法和使用场景

  1. useState
import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0); // 声明状态变量及其setter函数

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
  • 使用场景: 在函数组件中管理状态,如计数器、表单控件等。
  • 注意事项:
    • useState只接受一个参数作为初始状态
    • 状态更新会引起组件重新渲染,因此避免在主体渲染中调用setState
    • 可以使用多个useState管理不同状态
  1. useEffect
import React, { useState, useEffect } from 'react';

function Example() {
  const [data, setData] = useState([]);

  useEffect(() => {
    // 模拟网络请求
    const fetchData = setTimeout(() => {
      setData([1, 2, 3]);
    }, 2000);

    // 清理副作用
    return () => clearTimeout(fetchData);
  }, []); // 空数组确保只运行一次

  return <ul>{data.map(item => <li key={item}>{item}</li>)}</ul>;
}
  • 使用场景: 执行有副作用的操作,如发送网络请求、订阅事件等。
  • 注意事项:
    • 第二个参数是一个数组,用于指定effect的依赖项,只有依赖项变化时才会重新执行
    • 返回一个清理函数,用于清理副作用,如取消订阅等
    • 空数组[]表示只在组件挂载和卸载时执行
  1. useContext
import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button style={{ background: theme }}>I am styled by theme context!</button>;
}
  • 使用场景: 跨层级组件传递数据,避免手动逐层传递 props。
  • 注意事项:
    • 需要先使用createContext创建Context对象
    • 上层组件使用Provider提供数据
    • 下层组件使用useContext获取数据
  1. useReducer
import React, { useReducer } from 'react';
const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}
  • 使用场景: 状态逻辑较复杂时,可以使用 Reducer 模式优化状态管理。
  • 注意事项:
    • useReducer接收两个参数,第一个是reducer函数,第二个是初始状态
    • reducer函数根据不同的action决定如何更新状态
    • dispatch用于发送action从而更新状态
  1. useCallback
import React, { useState, useCallback } from 'react';
function Parent() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <input value={name} onChange={e => setName(e.target.value)} />
      <Child handleClick={handleClick} />
      <p>Count: {count}</p>
    </div>
  );
}

const Child = React.memo(({ handleClick }) => {
  console.log('Child rendered');
  return <button onClick={handleClick}>Click me</button>;
});
  • 使用场景: 缓存函数实例,避免组件重新渲染时重复创建函数实例。
  • 注意事项:
    • 第二个参数是一个数组,用于指定依赖项,只有依赖项变化时才会重新创建函数实例
    • 通常与React.memoshouldComponentUpdate一起使用,提高性能
  1. useMemo
import React, { useState, useMemo } from 'react';
function App() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  const data = useMemo(() => {
    return { count, name };
  }, [count, name]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <input value={name} onChange={e => setName(e.target.value)} />
      <Display data={data} />
    </div>
  );
}

function Display({ data }) {
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
  • 使用场景: 缓存计算结果,避免重复计算。
  • 注意事项:
    • 第二个参数是一个数组,用于指定依赖项,只有依赖项变化时才会重新计算
    • 如果计算量非常小,使用可能引起额外开销,适合使用在计算量较大的场景
  1. useRef
import React, { useRef, useEffect } from 'react';

function App() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return (
    <div>
      <input ref={inputRef} type="text" />
    </div>
  );
}
  • 使用场景: 获取DOM元素或保存可变值的引用。
  • 注意事项:
    • useRef返回一个可变的ref对象,其current属性被初始化为传入的参数
    • ref对象在组件的整个生命周期内保持不变
  1. useImperativeHandle
import React, { useRef, forwardRef, useImperativeHandle } from 'react';
const Input = forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
  }));

  return <input ref={inputRef} {...props} />;
});

const App = () => {
  const inputRef = useRef();

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <Input ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
};
  • 使用场景: 使父组件可以获取子组件实例的句柄,调用子组件的方法。
  • 注意事项:
    • 需要配合forwardRef来使用
    • 父组件通过ref获取子组件实例,子组件通过useImperativeHandle定义暴露给父组件的方法
  1. useLayoutEffect
import React, { useLayoutEffect, useState } from 'react';

function App() {
  const [value, setValue] = useState(0);

  useLayoutEffect(() => {
    if (value === 0) {
      setValue(10 + Math.random() * 200);
    }
  }, [value]);

  console.log('render', value);

  return (
    <div onClick={() => setValue(0)}>
      Value: {value}
    </div>
  );
}
  • 使用场景: 在DOM更新后立即执行一些同步操作,例如获取DOM元素位置等。
  • 注意事项:
    • useEffect的执行时机不同,useLayoutEffect会在所有DOM变更之后同步执行
      -如果操作非常昂贵,应该考虑使用useEffect以免阻塞浏览器渲染
  1. useDebugValue
import React, { useDebugValue, useState } from 'react';
function useCustomHook(initialValue) {
  const [value, setValue] = useState(initialValue);
  useDebugValue(`Current value: ${value}`);
  return [value, setValue];
}

function App() {
  const [value, setValue] = useCustomHook(0);
  return (
    <div>
      <p>Value: {value}</p>
      <button onClick={() => setValue(value + 1)}>Increment</button>
    </div>
  );
}
  • 使用场景: 在 React 开发者工具中显示自定义 Hook 的标签,方便调试。
  • 注意事项:
    • 只在开发环境下有效,生产环境会被自动忽略
    • 第一个参数是一个格式化的字符串,用于显示标签内容

以上是一些常用 Hooks 的示例代码、使用场景和注意事项。在实际开发中,应根据具体需求合理选择和组合使用 Hooks,以提高代码的可读性和可维护性。同时也要注意 Hooks 的使用规则和限制,避免出现潜在的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/496660.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++模板类和模板函数

模板类 #include<bits/stdc.h> using namespace std; template<typename T> class People{public:People(T name):name_(name){}protected:T name_; }; class A:public People<string>{public:A(string name): People(name){}void print(){std::cout<<…

鸿蒙OS开发实例:【手撸服务卡片】

介绍 服务卡片指导文档位于“开发/应用模型/Stage模型开发指导/Stage模型应用组件”路径下&#xff0c;说明其极其重要。 本篇文章将分享实现服务卡片的过程和代码 准备 请参照[官方指导]&#xff0c;创建一个Demo工程&#xff0c;选择Stage模型 鸿蒙OS开发更多内容↓点击…

eNSP-GRE简单配置

目录 IP配置 公网全网通 配置隧道 路由配置 检测 1、按照图示配置 |P 地址 IP配置 配置主机IP地址&#xff1a; PC1&#xff1a; PC2&#xff1a; R1&#xff1a; <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sysname R1 [R1]int g 0…

mysql--事务四大特性与隔离级别

事务四大特性与隔离级别 mysql事务的概念事务的属性事务控制语句转账示例 并发事务引发的问题脏读脏读场景 不可重复读幻读幻读场景 事务的隔离级别读未提交读已提交可重复读&#xff08;MySQL默认&#xff09; 总结 mysql事务的概念 事务就是一组操作的集合&#xff0c;他是一…

春秋云境CVE-2022-24663

简介 远程代码执行漏洞&#xff0c;任何订阅者都可以利用该漏洞发送带有“短代码”参数设置为 PHP Everywhere 的请求&#xff0c;并在站点上执行任意 PHP 代码。P.S. 存在常见用户名低权限用户弱口令 正文 进入首页我们没看到任何有价值的东西&#xff0c;那么就只好去寻找…

【LeetCode】升级打怪之路 Day 28:回溯算法 — 括号生成 删除无效的括号

今日题目&#xff1a; 22. 括号生成301. 删除无效的括号 参考文章&#xff1a; 回溯算法&#xff1a;括号生成回溯算法&#xff1a;删除无效的括号 这是两道使用回溯算法来解决与括号相关的问题&#xff0c;具备一定的难度&#xff0c;需要学习理解。 通过第一道题“括号生成”…

Vivado使用(2)——综合运行与OOC

目录 一、综合运行 二、OOC 2.1 如何设置 OOC 模块 2.2 存根文件和黑盒属性 2.3 使用限制 2.4 另一种设置方法 一、综合运行 一个“运行&#xff08;run&#xff09;”是指定义和配置设计在综合过程中的各方面&#xff0c;包括&#xff1a;使用到约束&#xff0c;针对的…

Java常见限流用法介绍和实现

目录 一、现象 二、工具 ​​​​​​1、AtomicInteger,AtomicLong 原子类操作 ​​​​​​2、RedisLua ​​​​​​3、Google Guava的RateLimiter 1&#xff09; 使用 2&#xff09; Demo 3&#xff09; 优化demo 4、阿里开源的Sentinel 三、算法 1、计数限流 &…

Java实现猜数字游戏:编程入门之旅

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

HDFS的Shell操作及客户端配置方法

HDFS进程启停命令 Hadoop HDFS组件内置了HDFS集群的一键启停脚本。 $HADOOP_HOME/sbin/start-dfs.sh&#xff0c;一键启动HDFS集群$HADOOP_HOME/sbin/stop-dfs.sh&#xff0c;一键关闭HDFS集群 执行原理&#xff1a; 在执行此脚本的机器上&#xff0c;启动&#xff08;关闭&…

二叉树|538.把二叉搜索树换为累加树

力扣题目链接 class Solution { private:int pre 0; // 记录前一个节点的数值void traversal(TreeNode* cur) { // 右中左遍历if (cur NULL) return;traversal(cur->right);cur->val pre;pre cur->val;traversal(cur->left);} public:TreeNode* convertBST(Tre…

阎淑萍:老母猪戴口罩还挺重视这张老脸啊,赵本山:我也相当副科级呀!

阎淑萍&#xff1a;老母猪戴口罩还挺重视这张老脸啊&#xff0c;赵本山&#xff1a;我也相当副科级呀&#xff01; ——小品《老拜年》&#xff08;上&#xff09;的台词 《老拜年》 是赵本山、阎淑萍、王中青、苏杰在《1993年中央电视台春节联欢晚会》上表演的小品&#xff0…

web全栈架构师第16期教程

教程介绍 互联网时代已进入后半场&#xff0c;行业环境发生了显著变化。互联网人&#xff0c;尤其是技术人员&#xff0c;如何在加速更迭的技术浪潮中持续充电&#xff0c;提升自身价值&#xff0c;是当下必须面对的挑战。课程涉及了现下前端实际开发时所需要的各块内容&#…

发现数据异常波动怎么办?别慌,指标监控和归因分析来帮你

企业搭建完善、全面的指标体系是企业用数据指导业务经营决策的第一步。但是做完指标之后&#xff0c;对指标的监控&#xff0c;经常被大家忽视。当指标发生了异常波动&#xff08;上升或下降&#xff09;&#xff0c;需要企业能够及时发现&#xff0c;并快速找到背后真实的原因…

Xcode删除原本的Git,再添加新的git

本文参考&#xff1a;Xcode怎么删除原本git,在重新设置新的git地址_ios xcode 删除原本git-CSDN博客 开发中会有一个问题。Xcode项目A 提交到Git服务器server1&#xff0c;此时项目A内部已经存在一个Git文件&#xff0c;与server1相关联。 此时你想将项目A提交到 另一个Git…

算法打卡day30|贪心算法篇04|Leetcode 860.柠檬水找零、406.根据身高重建队列、452. 用最少数量的箭引爆气球

算法题 Leetcode 860.柠檬水找零 题目链接:860.柠檬水找零 大佬视频讲解&#xff1a;柠檬水找零视频讲解 个人思路 5元最通用&#xff0c;然后是10元&#xff0c;所以如果是对于20元找零直接先找10元&#xff0c;也涉及到贪心的思想&#xff0c;可以用贪心算法。 解法 贪心法…

加密流量分类torch实践5:TrafficClassificationPandemonium项目更新3

加密流量分类torch实践5&#xff1a;TrafficClassificationPandemonium项目更新3 更新日志 代码已经推送开源至露露云的github&#xff0c;如果能帮助你&#xff0c;就给鼠鼠点一个star吧&#xff01;&#xff01;&#xff01; 我的CSDN博客 我的Github Page博客 3/23日更新…

打造核心竞争力:高效Web系统数据中台的设计与实践_光点科技

在数字化的浪潮中&#xff0c;数据已经成为企业赖以生存和发展的核心资源。一个高效的Web系统数据中台&#xff0c;能够赋予企业在激烈的市场竞争中立于不败之地的能力。本文将深入探讨如何设计和实施一个能够提升企业数据管理水平和支持业务决策的高效数据中台架构。 数据中台…

基于Python实现多功能翻译助手(下)

为了将上述步骤中的功能增强与扩展具体化为代码&#xff0c;我们将实现翻译历史记录功能、翻译选项配置以及UI的改进。 翻译历史记录功能 import json # 假设有一个用于存储历史记录的json文件 HISTORY_FILE translation_history.json # 初始化历史记录列表 translati…

数组---

1、数组的定义 Java中&#xff0c;数组存储固定大小的同类型元素。 数组是多个相同类型数据按一定顺序排列的集合&#xff0c;并使用一个名字命名&#xff0c;通过编号的方式对这些数据进行统一的管理。 数组的特点&#xff1a; 数组本身是引用数据类型&#xff0c;但数组中的…