React Hooks 的两个坑点

news2025/2/22 12:35:53

React Hooks 使用注意事项

Area: Hooks
Date: February 10, 2025
Important: 🌟🌟🌟

React Hooks 注意事项

要点:

  • useState 的初始化值 只在第一次渲染时计算,并且这个值不会随着组件重新渲染而更新。
  • useEffect 可能出现死循环,比如处理请求接口时,依赖项绑定对象类型数据,会死循环。


useState 的初始值问题

Case:useState 的初始化值 只在第一次渲染时计算,并且这个值不会随着组件重新渲染时更新。

理解:useState 的初始化值只在组件的第一次渲染时生效,不会随着 propsstate 的变化而更新。

2025-02-16 23.03.54.gif

import React, { useState } from 'react'

// 子组件
function Child({ userInfo }) {
  // render: 初始化 state
  // re-render: 只恢复初始化的 state 值,不会再重新设置新的值
  //            只能用 setName 修改
  const [name, setName] = useState(userInfo.name)

  return (
    <div>
      <p>Child, props name: {userInfo.name}</p>
      <p>Child, state name: {name}</p>
    </div>
  )
}

function App() {
  const [name, setName] = useState('双越')
  const userInfo = { name }

  return (
    <div>
      <div>
        Parent &nbsp;
        <button onClick={() => setName('慕课网')}>setName</button>
      </div>
      <Child userInfo={userInfo} />
    </div>
  )
}

export default App

解决方案:使用 useEffect 来监听 userInfo 的变化,并在变化时更新 name

import React, { useState, useEffect } from 'react'

function Child({ userInfo }) {
  const [name, setName] = useState(userInfo.name)

  // 使用 useEffect 来监听 userInfo.name 的变化并更新 name
  useEffect(() => {
    setName(userInfo.name)
  }, [userInfo.name])  // 当 userInfo.name 发生变化时更新 name

  return (
    <div>
      <h1>Child, Props name: {userInfo.name}</h1>
      <h1>Child, state name: {name}</h1>
    </div>
  )
}

function App() {
  const [name, setName] = useState('Nathan')
  const userInfo = {
    name,
  }
  return (
    <div>
      <h1>UserName</h1>
      <button onClick={() => setName('XXXX')}>Change Name</button>
      <Child userInfo={userInfo} />
    </div>
  )
}

export default App



useEffect 的死循环问题

Case:useEffect 死循环

理解:处理请求接口时,依赖项绑定对象类型数据,会死循环。

2025-02-16 23.24.16.gif

import { useState, useEffect } from 'react'
import axios from 'axios'

// 传入 config,类型为对象
function useAxios(url, config = {}) {
  const [loading, setLoading] = useState(false)
  const [data, setData] = useState()
  const [error, setError] = useState()

  useEffect(() => {
    setLoading(true)
    axios
      .get(url) // 发送一个 get 请求
      .then(res => setData(res))
      .catch(err => setError(err))
      .finally(() => setLoading(false))
  }, [url, config])

  return [loading, data, error]
}

export default useAxios

分析:

1-useEffect 和依赖项的关系:

useEffect 中,[url, config] 是依赖项数组。这意味着当 urlconfig 发生变化时,useEffect 会重新执行。

2-对象 config 的变化:

在 JavaScript 中,对象(如 config)是引用类型。如果每次重新渲染时,config 的引用发生了变化,即使它的内容相同,React 也会认为它发生了变化,从而触发 useEffect 的重新执行。

这就导致了一个问题:每次组件重新渲染时,config 对象的引用可能会发生变化,即使它的值没有改变。这会导致 useEffect 被反复调用,进而每次发起请求。

注:这里 React 底层使用的是 Object.is() 进行比较

image.png

总结无限请求的原因:

  • 每次组件渲染时,config 会被认为是新的对象(即使它的内容没有变化),从而触发 useEffect 重新执行。
  • useEffect 执行时会发起请求,且请求可能会导致 config 的变化(如果在请求完成后更新了 config,即使没有显式更新也可能影响父组件中的 config)。
  • 因此,useEffect 会再次被触发,导致请求不断发起,形成无限请求的循环。

解决方案:

基础方案:

useEffect 依赖项不要放置对象类型。可在之前将对象解构,useEffect依赖项中放置基本类型值

另一种方案:

如果你希望在 config 变化时也重新发送请求,你可以使用 useMemo 来确保只有在 config 内容变化时才触发请求:

import { useState, useEffect, useMemo } from 'react'
import axios from 'axios'

function useAxios(url, config = {}) {
  const [loading, setLoading] = useState(false)
  const [data, setData] = useState()
  const [error, setError] = useState()

  // 使用 useMemo 来确保 config 引用只有在实际变化时才会更新
  const memoizedConfig = useMemo(() => config, [JSON.stringify(config)])

  useEffect(() => {
    setLoading(true)
    axios
      .get(url, memoizedConfig) // 使用 memoizedConfig 而非原始 config
      .then(res => setData(res))
      .catch(err => setError(err))
      .finally(() => setLoading(false))
  }, [url, memoizedConfig])

  return [loading, data, error]
}

export default useAxios

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Oracle启动与关闭(基础操作)

11g读取参数文件的顺序 9i之前&#xff0c;只有静态参数文件pfile文件。 9i开始&#xff0c;引入了动态参数文件spfile文件。 Windows&#xff1a; %ORACLE_HOME%\database SPFILEORCL就是动态参数文件 Linux&#xff1a; $ORACLE_HOME/dbs 11g中&#xff0c;启动数据库。…

新版电脑通过wepe安装系统

官方下载链接 WIN10下载 WIN11下载 微PE 启动盘制作 1&#xff1a;选择启动盘的设备 2&#xff1a;选择对应的U盘设备&#xff0c;点击安装就可以&#xff0c;建议大于8g 3&#xff1a;在上方链接下载需要安装的程序包&#xff0c;放入启动盘&#xff0c;按需 更新系统 …

Jmeter断言、关联、录制脚本

Jmeter断言 断言&#xff1a;让程序自动判断预期结果和实际结果是否一致 提示: Jmeter在请求的返回层面有个自动判断机制&#xff08;响应状态码 2xx:成功&#xff0c;4xx/5xx:失败&#xff09;但是请求成功了&#xff0c;并不代表结果一定正确&#xff0c;因此需要检测机制提…

SpringBoot速成(12)文章分类P15-P20

1.新增文章分类 1.Postman登录不上&#xff0c;可以从头registe->login一个新的成员:注意&#xff0c;跳转多个url时&#xff0c;post/get/patch记得修改成controller类中对应方法上写的 2.postman运行成功&#xff1a; 但表中不更新&#xff1a;细节有问题&#xff1a; c是…

RedHat8安装postgresql15和 postgis3.4.4记录及遇到的问题总结

安装包对照版本参考 UsersWikiPostgreSQLPostGIS – PostGIS 如果Red Hat系统上有旧版本的PostgreSQL需要卸载 在较新的Red Hat版本&#xff0c;使用dnf包管理器卸载&#xff1a;sudo dnf remove postgresql-server postgresql 旧版本&#xff0c;使用yum包管理器卸载 sudo y…

深入解析计算机网络请求头:常见类型与安全性影响

目录 1. Host 2. User-Agent 3. Cookie 4. Referer&#xff08;或 Referrer&#xff09; 5. Authorization 6. Content-Type 7. Content-Length 8. Origin 9. X-Forwarded-For (XFF) 10. Upgrade-Insecure-Requests 11. X-Frame-Options 12. Cache-Control 13. Ac…

VisoMaster整合包及汉化

VisoMaster是个图片及视频换脸工具&#xff0c;速度快&#xff0c;性能十分强大。 VisoMaster安装有2种方式&#xff0c;根据官网指引安装也十分简单&#xff0c;在此就不重复&#xff0c;只说说安装过程中要注意的事项&#xff1a; 1、自动安装&#xff1a;需要在网络十分畅…

从安装软件到flask框架搭建可视化大屏(二)——创建一个flask页面,搭建可视化大屏,零基础也可以学会

附录&#xff1a;所有文件的完整代码 models.py # models/models.py from flask_sqlalchemy import SQLAlchemydb SQLAlchemy()class User(db.Model):__tablename__ user # 显式指定表名为 userid db.Column(db.Integer, primary_keyTrue)username db.Column(db.String(…

[JVM篇]垃圾回收器

垃圾回收器 Serial Seral Old PartNew CMS(Concurrent Mark Sweep) Parallel Scavenge Parallel Old G1 ZGC

DeepSeek专题:DeepSeek-V1核心知识点速览

AIGCmagic社区知识星球是国内首个以AIGC全栈技术与商业变现为主线的学习交流平台&#xff0c;涉及AI绘画、AI视频、大模型、AI多模态、数字人以及全行业AIGC赋能等100应用方向。星球内部包含海量学习资源、专业问答、前沿资讯、内推招聘、AI课程、AIGC模型、AIGC数据集和源码等…

SpringBoot+shardingsphere实现按月分表功能

SpringBootshardingsphere实现按月分表功能 文章目录 前言 ShardingSphere 是一套开源的分布式数据库中间件解决方案&#xff0c;旨在简化数据库分片、读写分离、分布式事务等复杂场景的管理。它由 Apache 软件基金会支持&#xff0c;广泛应用于需要处理大规模数据的系统中 一…

教程 | 从零部署到业务融合:DeepSeek R1 私有化部署实战指南

文章目录 1. 什么是 DeepSeek R1&#xff1f;a. 主要介绍a. 版本区别 2. 部署资源要求a. 硬件资源要求 3. 本地安装DeepSeek-R1a. 为什么选择本地部署&#xff1f;b. 部署工具对比c. 演示环境配置d. Ollama安装流程 4. 可视化工具a. 工具对比b. Open-WebUI部署 5. AI API应用a.…

分布式 NewSQL 数据库(TiDB)

TiDB 是一个分布式 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议&#xff0c;具有数据强一致的高可用特性&#xff0c;是一个不仅适合 OLTP 场景还适合 OLAP 场景的混合数据库。 TiDB是 PingCAP公司自主设计、研发的开源分布式关系型数据…

C语言-章节 1:变量与数据类型 ——「未初始化的诅咒」

在那神秘且广袤无垠的「比特大陆」上&#xff0c;阳光奋力地穿过「内存森林」中错综复杂的代码枝叶缝隙&#xff0c;洒下一片片斑驳陆离、如梦似幻的光影。林间的空气里&#xff0c;弥漫着一股浓郁的十六进制锈蚀味&#xff0c;仿佛在诉说着这片森林中隐藏的古老秘密。 一位零基…

HTML的入门

一、HTML HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是一种用来告知浏览器如何组织页面的标记语言。 超文本&#xff1a;就是超越了文本&#xff1b;HTML不仅仅可以用来显示文本(字符串、数字之类)&#xff0c;还可以显示视频、音频等…

闭源大语言模型的怎么增强:提示工程 检索增强生成 智能体

闭源大语言模型的怎么增强 提示工程 检索增强生成 智能体 核心原理 提示工程:通过设计和优化提示词,引导大语言模型进行上下文学习和分解式思考,激发模型自身的思维和推理能力,使模型更好地理解和生成文本,增强其泛用性和解决问题的能力。检索增强生成:结合检索的准确…

【图像加密解密】空间混沌序列的图像加密解密算法复现(含相关性检验)【Matlab完整源码 2期】

1、说明 本文给出详细完整代码、完整的实验报告和PPT。 环境&#xff1a;MATLAB2019a 复现文献&#xff1a;[1]孙福艳,吕宗旺.Digital image encryption with chaotic map lattices[J].Chinese Physics B,2011,20(04):136-142. 2、部分报告内容 3 部分源码与运行步骤 3.1 部…

QxOrm生成json

下载Qxorm-1.5版本 使用vs打开项目&#xff0c;直接生成即可&#xff1a; lib目录中会生成dll和lib文件 新建Qt项目使用Qxorm: 将QxOrm中上面三个目录拷贝到新建的Qt项目中 pro文件添加使用QxOrm第三方库 INCLUDEPATH $$PWD/include/ LIBS -L"$$PWD/lib" LIBS…

ASP.NET Core Web应用(.NET9.0)读取数据库表记录并显示到页面

1.创建ASP.NET Core Web应用 选择.NET9.0框架 安装SqlClient依赖包 2.实现数据库记录读取: 引用数据库操作类命名空间 创建查询记录结构类 查询数据并返回数据集合 3.前端遍历数据并动态生成表格显示 生成结果:

uniapp商城之首页模块

文章目录 前言一、自定义导航栏1.静态结构2.修改页面配置3.组件安全区适配二、通用轮播组件1. 静态结构组件2.自动导入全局组件3.首页轮播图数据获取三、首页分类1.静态结构2.首页获取分类数据并渲染四、热门推荐1.静态结构2.首页获取推荐数据并渲染3.首页跳转详细推荐页五、猜…