我发现了一个React、Vue等所有前端框架都存在的隐秘Bug?

news2025/1/9 2:35:29

什么 Bug?

昨天有个朋友请教了我一个问题,她在使用原生的 Details 元素封装一个手风琴组件。但是无论如何都不能按照预期工作。

起初我认为是她水平比较差,代码写的有问题。但是她一再向我保证绝对不是她的问题。所以我就抽出时间帮她看了一下。意外发现这一个框架的隐秘 Bug。

我把这个代码放到了码上掘金上,你可以看一下。

import React, { useState } from 'react';
import ReactDom from 'react-dom';

function App() {const [isOpen, setIsOpen] = useState(false)return (<><span>状态: {isOpen ? 'open' : 'closed'}</span><details open={isOpen}><summaryonClick={() => {setIsOpen(!isOpen)}}>Summary</summary>Details</details></>)
}

ReactDom.render(<App />, document.getElementById('app')); 

我们发现在组件的一开始并没有按照预期去渲染组件。之后的每一次点击,都不会按照预期去渲染。

为什么会这样?

原因在于 details 元素具有自身的状态,React 并不知道。

简单来说,这个问题在于 details 的 open 属性有两个数据来源:React 和浏览器。

更详细的讨论可以看这个 Github issue 。

首先我解释一下当第一次单击按钮时会发生什么:

1.summary 元素的 onClick 事件触发,状态 isOpen 从 false 变为 true。
2.React 重新渲染组件,将 details 元素的 open 属性设置为 true。
3.details 元素的默认行为会切换自身 open 状态,将 open 设置为 false,但 React 并不知道。

所以这就是 details 元素最终没有将 open 属性设置为 true 的原因,而我们的 isOpen 状态依然是 true。

第二次点击:

1.summary 元素的 onClick 处理程序 被触发,切换 isOpen 到 false.
2.React 重新渲染,发现 details 已经关闭,所以它不会去改变它。
3.details 元素的默认行为再次切换它的 open 状态。现在是 false,所以它会把 open 状态改变为 true,而 React 仍然不知道。

在此之后,一切都会打破。

怎么解决?

e.preventDefault

解决思路其实很简单,只要不让浏览器乱动状态就可以了。我们可以使用 e.preventDefault 来禁止浏览器的默认行为。这样就只有 React 能够控制它的状态了。

toggle

除了上面的方法外,还有一种方法是通过 details 的 toggle 事件来处理它。

function App() {const [isOpen, setIsOpen] = useState(false)return (<><span>状态: {isOpen ? 'open' : 'closed'}</span><detailsopen={isOpen} onToggle={() => {setIsOpen(!isOpen)}}><summary>Summary</summary>Details</details></>)
} 

这样似乎正常了。

但是很快我的朋友又遇到了新的麻烦,她在 details 中有一个按钮,这个按钮可以改变 isOpen 的状态。

function App() {const [isOpen, setIsOpen] = useState(false)return (<><span>状态: {isOpen ? 'open' : 'closed'}</span><detailsopen={isOpen}onToggle={() => {setIsOpen(!isOpen)}}><summary>Summary</summary>Details<button onClick={() => setIsOpen(!isOpen)}>切换状态</button></details></>)
} 

当点击这个按钮时,浏览器就抽风了,进入了死循环状态。

我又试着帮她解析了一下这个问题的原因:

1.按钮的 onClick 事件会切换 isOpen,同时会更改 details 的 open 属性。
2.open 属性的变化会触发 onToggle 事件。
3.onToggle 事件会再次切换 isOpen 的状态。同时改变了 details 的 open 属性,这时又回到了第 2 步,所以进入了无限循环状态。

这个 Bug 是 React 框架独有的吗?

虽然朋友解决了这个问题,但是她也向我吐槽 React 难用。

我很好奇这个问题是 React 独有的问题吗?其他类似的框架,比如 Soild、Svelte 和 Vue 它们会有这个问题吗?

于是我尝试了其他所有框架,发现它们都有这个问题。

Vue 的代码如下:

<template><span>状态: {{isOpen ? 'open' : 'closed'}}</span><details :open="isOpen"><summary @click="()=> {isOpen = !isOpen}">Summary</summary>Details</details>

</template>

<script> import { defineComponent, ref } from 'vue';

export default defineComponent({setup() {const isOpen = ref(false);return {isOpen};},
}); </script> 

我也放到了码上掘金上,你可以看一下。

这个 Bug 到底是谁的锅?

鉴于所有的框架都有这个问题,所以我认为它不应该是框架的问题。

于是我尝试用原生的 JavaScript 来编写这段程序。

<!DOCTYPE html>
<html><body><span>状态: closed</span><details><summary>Summary</summary>Details</details><script> const span = document.querySelector('span')const details = document.querySelector('details')const summary = document.querySelector('summary')let isOpen = falsesummary.addEventListener('click', () => {if (isOpen) {isOpen = falsespan.textContent = '状态: closed'details.removeAttribute('open')return}isOpen = truespan.textContent = '状态: open'details.setAttribute('open', '')}) </script></body>
</html> 

现在看来,这似乎是 details 这个元素的底层工作原理的问题,和框架无关。

能够完美解决的唯一办法就是通过 e.preventDefault 来禁止掉浏览器默认行为,让 JavaScript 中的变量成为唯一的数据源。

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

DP2515国产带SPI接口CAN总线控制器芯片兼容替代MCP2515/MCP2515-I/ST

目录什么是CAN&#xff1f;DP2515简介芯片特性参考原理图什么是CAN&#xff1f; CAN是控制器局域网络(Controller Area Network, CAN)的简称&#xff0c;是如今是国际上应用最广泛的现场总线之一&#xff0c;是ISO国际标准化的串行通信协议。在汽车产业中&#xff0c;出于对安…

项目管理必备,教你如何制作甘特图

甘特图是项目管理中常用的工具&#xff0c;又被称为横道图。 由表格和条形图组成&#xff0c;左侧显示项目中所有的任务及时间&#xff0c;右侧一条状进度条显示项目每个任务的进度。 因为它极其好用&#xff0c;不仅在比较大型和复杂的项目中被广泛使用&#xff0c;在日常工…

iPhone 微信多开,如何在苹果手机上安装多个微信,爱思助手怎么用?IPA文件怎么弄?

苹果实现微信多开,用爱思助手就能实现,简单易上手。爱思助手怎么用?IPA文件怎么弄? 设备:Mac(11.6)/14pm 助手:爱思助手 需求:在最新的苹果手机上实现微信多开 博主上个月底抢的14pm终于到手了,之前多开微信一直用的大灰免费版的,怎么说呢?挺好用的但是不稳定,…

简单的有限状态机(FSM)的示例一

一个简单的有限状态机&#xff0c; 三种状态&#xff1a; 停止状态运行状态暂停状态 三个事件 StartPauseStop 状态转换说明&#xff1a; Stopped状态&#xff1a;通过Start事件转换为Running状态Running状态&#xff1a;通过Pause事件可转换为Pause状态Pause状态&#…

什么是零知识证明(ZK Proof)?Web2.0通往Web3.0的入口技术

古老的难题 女&#xff1a;你爱我吗&#xff1f; 男&#xff1a;爱&#xff01; 女&#xff1a;怎么证明&#xff1f; 男&#xff1a;…… 零知识证明的定义 零知识证明(Zero-Knowledge Proof)也叫做最小泄露证明&#xff0c;能充分证明自己是某种权益的合法拥有者&#xff0c…

【Docker】第四章 容器管理

4.1 创建容器常用选项 指令 描述 -i, --interactive 交互式 -t, --tty 分配一个伪终端 -d, --detach 运行容器到后台 -a, --attach list 附加到运行的容器 --dns list 设置DNS服务器 -e, --env list 设置环境变量 --env-file list 从文件读取环境变量 -p, --p…

知识点14--搭建k8s本地测试集群

首先要做安装前的准备&#xff1a; 1、最少三台节点&#xff0c;CentOS 7系统&#xff0c;每台不低于4核4G资源&#xff0c;并配置host域名 [roothdp1 ~] cat /etc/hosts 192.168.88.186 hdp1 192.168.88.187 hdp2 192.168.88.188 hdp32、所有节点保证时间同步、并做SSH互信 …

离散数学与组合数学-数理逻辑-01命题与联结词

文章目录1. 命题与联结词1.1 命题1.2 常用联结词1.3 命题公式1.4 命题的等值演算与推理等价关系式基本等价式1. 命题与联结词 1.1 命题 命题&#xff1a;我们对确定对象做出的陈述句称为命题&#xff08;propositions and statements 命题或陈述&#xff09;。当判断为真时&a…

《小猫猫大课堂》2—开启C语言的世界,喵!

更新不易&#xff0c;麻烦多多点赞&#xff0c;欢迎你的提问&#xff0c;感谢你的转发&#xff0c; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我…

学不会的python之正则表达式详解(re模块)

本篇博客介绍了正则表达式与在python中的应用(re模块)&#xff0c;及一些在开发中常见的模式示例。参考书籍《python核心编程(第三版)》 学不会的python之正则表达式正则表达式(模式)简介正则应用搜索与匹配注意特殊符号与字符择一匹配匹配单个字符注意问题起始、结尾、单词边界…

天津教育杂志天津教育杂志社天津教育编辑部2022年第35期目录

卷首语《天津教育》投稿&#xff1a;cn7kantougao163.com 强化教学保障意识 助力基础教育又好又快发展 本刊编辑部; 1 本刊视线_关注 家校协同下的青少年心理健康问题探讨 袁玉萍; 4-6 本刊视线_学校体育 中学体育课程主体活动教学模式的实施 张强;李聚虎; 7-9 本刊…

Python制作粒子烟花,提前开始跨年?

前言 跨年倒计时20天&#xff1f;我已经开始整烟花了&#xff0c;虽然不是很好看吧&#xff0c;但是也能将就看看 &#x1f625; 这个的背景图&#xff0c;音乐&#xff0c;还有文字都是可以自己修改的哦 效果展示 导入库 import random import pygame as py import tkinte…

CENTOS上的网络安全工具(十五)cascade的部署

这一篇&#xff0c;我们尝试在CentOS上安装并运用一款“小众”安全工具——Cascade。这个工具给人的感觉只是作为验证ATT&CK理念的一个存在&#xff0c;而且由于其运转还需要依托CAR&#xff0c;所以对数据的处理停留在主机log类的层面&#xff0c;可能暂时还不太受安全公司…

【Lilishop商城】No3-3.模块详细设计,会员信息(会员基本信息)、店铺设置(店铺信息、配送模板)的详细设计

仅涉及后端&#xff0c;全部目录看顶部专栏&#xff0c;代码、文档、接口路径在&#xff1a; 【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑&#xff0c;其中重点包括接口类、业务类&#xff0c;具体的结合源代码…

Briefings in Bioinformatics2021 | 从头药物设计的深度生成模型的综合性评估

论文标题&#xff1a;Comprehensive assessment of deep generative architectures for de novo drug design 论文地址&#xff1a;Comprehensive assessment of deep generative architectures for de novo drug design | Briefings in Bioinformatics | Oxford Academic 一…

JMeter的三种参数化方式

一、 用户定义的变量 1.线程组-配置元件添加用户定义的变量 2.引用变量 ${变量} 二、 csv Data Set config &#xff08;1&#xff09;csv Data Set config之.CSV 1.造.csv格式文件的数据 2.设置CSV数据文件 3.消息体数据&#xff0c;引用变量名.{变量名} 4.设置线程组&…

关于Elasticsearch查询(match、match_phrase、query_string和term)

由上图看出&#xff0c; QueryBuilder 是整个查询操作的核心&#xff0c;决定了查询什么样的数据和期望得到什么结果这些核心的问题。 QueryBuilder 只是一个接口&#xff0c;需要具体的实体类才可以。那么如何创建 QueryBuilder 的实例呢&#xff1f;有两种方式 通过 QueryB…

AOP开发明确的的事项

12.2. AOP开发明确的的事项 12.2.1、需要编写的内容 编写核心业务代码&#xff08;目标类的目标方法&#xff09; 编写切面类&#xff0c;切面类中有通知(增强功能方法) 在配置文件中&#xff0c;配置织入关系&#xff0c;即将哪些通知与哪些连接点进行结合 12.2.2、AOP 技…

什么是MinIO

本文为joshua317原创文章,转载请注明&#xff1a;转载自joshua317博客 什么是MinIO - joshua317的博客 什么是MinIO&#xff1f; MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。 MinIO提…

容灾演练月报 | 福莱特集团核心系统完成“跨云”容灾切换演练

11月&#xff0c;美创科技携手福莱特集团、金华银行、稠州银行、慈溪市卫健委及医疗行业等总计19家用户完成容灾切换演练&#xff0c;其中完成2次灾难切换&#xff0c;有效验证了各用户单位容灾系统的可靠性及高可用性&#xff01; 本月典型案例&#xff1a;福莱特集团 福莱特集…