现代前端开发者的自我迷失,你还会前端基础知识吗?

85621ef8fdcee7c52c54c9d3ba3ab001.jpeg

通常来说,我认为情况并不算糟糕,熟练的手可以几乎做到一切。然而,最近我注意到一些事情改变了我对这个行业的看法。似乎在这些无尽的趋势、范式和新奇玩意中,我们忘记了前端开发的支柱(意思是忘记了基础知识,没有轮子没法写代码了)。

在这篇文章中,我想分享一些最近项目中的代码片段,并试着解释一下我的想法。不多说了,让我们开始吧!

cce02d1e24f28598871226964d175be9.jpeg

文章目录

  1. 无休止的过度复杂化

  2. 来自1993年的错误

  3. 万恶之源

  4. 几个重要提示

无休止的过度复杂化

这里我们有最基本的卡片组件(Card component),它有一个可选的头部(header)属性。如果这个属性存在,我们就将其渲染到一个特定类名的包裹div中。

const Card = ({ children, header }) => {
  return (
    <div className="card">
      {header && <div className="card__header">{header}</div>}
      {children}
    </div>
  );
};

在简单的情况下,一切都可以正常工作。在这种情况下,<Card />不会渲染头部,而在这种情况下会渲染头部:<Card header={"I am header"} />。问题开始出现在头部内容是动态的,可以返回实际内容或null的情况下:<Card header={<CardHeader />} />。我们的条件语句{header && <div />}无法检测到这种情况,会渲染一个空的div。

一位开发者试图解决这个问题。他想:“等等,我们可以检查div的内容,如果为空就隐藏它!”这大概是他写的代码:

const Card = ({ children, header }) => {
  const headerRef = useRef();

  useEffect(() => {
    const hasContent = headerRef.current?.childNodes.length > 0;
    headerRef.current.style.display = hasContent ? "block" : "none";
  });

  return (
    <div className="card">
      {header && (
        <div ref={headerRef} className="card__header">
          {header}
        </div>
      )}
      {children}
    </div>
  );
};

另一个开发人员在代码审查中注意到,这段代码只在初始渲染时起作用。如果页脚是异步更新的,useEffect将不会被调用。经过长时间的讨论,开发人员决定将注意力转向MutationObserver。

在他们的讨论中,他们也向我征求了建议。老实说,向他们展示我的方法真的很有趣。只需要使用普通的CSS就足以解决这个问题。

.card__header:empty {
  display: none;
}

开发人员习惯于过度复杂化任务,以至于他们甚至没有检查CSS的基本功能。

来自1993年的错误(老掉牙”的问题或错误)

在我之前的项目中,我们有一个侧边栏小部件,它必须拉伸到最大高度,但不重叠头部和底部。大致的公式如下:100% - headerHeight - footerHeight。

这个解决方案在所有页面上都很顺利地工作,除了其中一个页面。在那个页面上,footerHeight 突然等于 0。发现这个 bug 的开发人员深入挖掘后发现,document.querySelector('footer')返回 null,但是页脚仍然在页面上呈现。你认为他做了什么?是的,又用了MutationObserver。

延伸阅读:什么是 MutationObserver

MutationObserver 是一个 JavaScript API,它允许开发人员监视DOM树的更改。当DOM元素发生变化时,MutationObserver 可以触发回调函数来执行相应的操作。它可以用于动态地更新页面内容,特别是在 Web 应用程序中,它可以用于处理数据的异步加载和动态更新,从而提高用户体验。然而,在某些情况下,使用 MutationObserver 可能会导致过度复杂化,因此开发人员应该在使用它时谨慎考虑,并确保它是必需的解决方案。

这让我感到很奇怪,于是我决定寻找另一种解决方案。我找到了它,只需要交换几行代码就行了...

<html>
<head></head>
<body>
  <header></header>
  <main id="root"></main>
  <script src="index.js"></script>
  <footer></footer>
</body>
</html>

某种原因,<script />标签在页脚之前出现了。<script />是同步调用的,在页脚不存在的情况下,无法测量它的高度。我只是交换了这几行代码,一切都开始正常工作了。

现在的开发人员高度依赖于像webpack-plugin等现代工具。所以当他们需要自己编写一些 HTML 时,他们立即放弃了。但这有什么难的呢?

万恶之源

React hooks 在 React 中是最好的东西,同时也是最糟糕的东西。一方面,它们增加了灵活性,并提供了一种优雅的处理状态的方式。另一方面,它们大大增加了代码复杂性,并使错误更容易发生。

仔细阅读文档并理解如何正确使用这些东西似乎并不难。但是有些开发人员忽略了这个明显的步骤,开始在没有完全理解它们用途的情况下使用 hooks。特别是当涉及到优化和臭名昭著的 useMemo 和 useCallback 时。现在每个开发人员都在没有明确原因的情况下优化整个应用程序。

❗️如果您想深入探讨这个话题,我强烈建议您查看这篇关于 useMemo 的文章。

https://javascript.plainenglish.io/stop-using-usememo-now-e5d07d2bbf70

让我们一起看一下这个“关键”的优化。这不是我专门为这篇文章编写的虚构代码。实际上,我从我的一个项目中获取了这个代码片段。

const loaded = useMemo(() => {
    return submitted && !loading && !error;
  }, [submitted, error, loading]);

经过这个优化后,应用程序的性能简直“一飞冲天”!正如您所了解的,这完全是无用的,甚至稍微会影响应用程序的首次加载。老实说,我仍然不明白写这个代码的真正目的是什么。

通常,想当然并不去考虑其他方面是容易的。但是做一些自己的小型研究可能需要一些额外的工作,但这仍然比在不完全理解工具或优化技术的情况下盲目地应用它们更好。通过自己的研究,我们可以更好地理解如何正确地使用工具和技术,以及何时使用它们,从而避免不必要的代码复杂性和错误。

几个重要提示

这种情况看起来确实很令人沮丧。开发人员开始忘记基本技术,并在新技术和方法的混乱中失去了批判性思维。

然而,在我看来,解决这个问题并不是很困难。为了总结上面的一切,我想向您展示这些直接的观点。请给我您的反馈!

  • 花一些时间去理解原生的 JavaScript。拥有强大的基础使您更容易检测错误的真正原因并快速修复它们。

  • 深入学习 HTML 和 CSS。您可以发现很多有用的属性、选择器和其他东西,可以取代大量的 JavaScript 代码。只需回想一下使用 :empty 选择器的例子。

  • 培养批判性思维能力。当然,您的团队领导教给您某些良好的实践和原则。然而,您不能盲目地遵循它们,因为这只会把您引向错误的方向。相反,尝试理解为什么某些事情是这样的,而不是另一种方式。

  • 记住 SOLID、YAGNI、KISS 和其他原则。如果一个简单的任务变成了一个混乱的解决方案的噩梦,请停下来,从不同的角度重新考虑它。可能是您太深入一个解决方案中,忘记了一些明显的东西。

延伸阅读:什么是 SOLID 原则?

SOLID 原则是面向对象设计中的五个基本原则:

1、单一职责原则 (SRP):一个类应该只有一个修改的理由。

2、开放封闭原则 (OCP):一个软件实体应该对扩展开放,对修改关闭。

3、里氏替换原则 (LSP):子类对象应该能够替换其基类对象。

4、接口隔离原则 (ISP):不应该强迫客户端依赖于它们不需要的接口。

5、依赖反转原则 (DIP):高级别模块不应该依赖于低级别模块,两者都应该依赖于抽象。

什么是YAGNI原则?

YAGNI 是 “You Ain’t Gonna Need It” 的缩写,意思是 “你不需要它”。这个原则建议开发人员只编写当前需要的代码,而不是试图预测未来的需求并编写相应的代码。这可以减少不必要的代码,简化代码库并提高代码的可维护性。

什么是KISS原则?

KISS 是 “Keep It Simple, Stupid” 的缩写,意思是 “保持简单,蠢瓜”。这个原则建议开发人员在设计和编写代码时保持简单。简单的代码更易于理解、维护和扩展,并且通常比复杂的代码更可靠。

结束

今天的分享就到这里,感谢你的阅读,希望能够帮助到你,文章创作不易,如果你喜欢我的分享,别忘了点赞转发,让更多有需要的人看到,最后别忘记关注「前端达人」,你的支持将是我分享最大的动力,后续我会持续输出更多内容,敬请期待。

原文:
https://javascript.plainenglish.io/we-forgot-frontend-basics-56c2b6590105

作者:Pavel Pogosov

非直接翻译,有自行改编和添加部分,翻译水平有限,难免有疏漏,欢迎指正

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

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

相关文章

【python】GIL全局锁

一、原理&#xff1a; 全局解释器锁&#xff08;Global Interpreter Lock&#xff0c;GIL&#xff09;规定全局范围内任意时候一个进程里只能同时执行一个线程。每一个线程在执行时&#xff0c;都会锁住GIL&#xff0c;以阻止别的线程执行&#xff1b;执行一段时间后&#xff…

OBCP第四章 SQL调优-SQL执行性能监控

(g)v$sql_audit 全局 SQL 审计表 基于虚拟表__all_virtual_sql_audit的视图&#xff0c; 该虚拟表对应的数据存放在一个可配置的内存空间中 由于存放这些记录的内存是有限的&#xff0c;因此到达一定内存使用量&#xff0c;会触发淘汰 可以用来查看每次请求客户端来源&…

【操作系统复习】第3章 处理机调度与死锁 3

死锁&#xff08;Deadlock&#xff09;&#xff1a;指多个进程在运行过程中因争夺资源而造成的一种僵局&#xff0c;当进程处于这种僵持状态时&#xff0c;若无外力作用&#xff0c;这些进程都将永远不能再向前推进。 对资源不加限制地分配可能导致进程间由于竞争资源而相互制约…

JavaSE学习总结(十三)Set集合HashSet集合LinkedHashSet集合TreeSet集合比较器的使用利用Set集合实现去重

JavaSE学习总结&#xff08;十三&#xff09;Set集合/HashSet集合/LinkedHashSet集合/TreeSet集合/比较器的使用/利用Set集合实现去重 一、Set集合 Set集合是Collection集合的一个子接口&#xff0c;实际上Set就是Collection&#xff0c;只是行为略有不同&#xff1a; Set集…

VUE3项目实现动态路由demo

文章目录1、创建vue项目2、安装常用的依赖2.1 安装elementUI2.2 安装axios2.3 安装router2.4 安装vuex2.5 安装store2.6 安装mockjs3、编写登录页面以及逻辑4、编写首页以及逻辑5、配置router.js6、配置store.js7、配置menuUtils.js&#xff08;动态路由重点&#xff09;8、配置…

树的前序遍历与中序遍历构造二叉树和树的中序遍历与后序遍历构造二叉树

目录 一.树的前序遍历与中序遍历构造二叉树 1.题目描述 2.问题分析 3.代码实现 二.树的中序遍历与后序遍历构造二叉树 1.题目描述 2.问题分析 3.代码实现 三.问题思考 一.树的前序遍历与中序遍历构造二叉树 1.题目描述 给定两个整数数组 preorder 和 inorder &#xf…

【机器学习】Logistic回归---学习笔记

Logistic回归学习笔记Logistic回归学习线路预备知识&#xff1a;建议先去B站学习一下信息量&#xff0c;熵&#xff0c;BL散度&#xff0c;交叉熵的概念。Logistic回归的函数模型损失最小化架构分类函数最大概率分类函数阈值分类函数Logistic回归的优化算法梯度下降随机梯度下降…

4.5--计算机网络之基础篇--2.网址到网页解析--(复习+深入)---好好沉淀,加油呀

1.浏览器做的第一步工作是解析 URL 对 URL 进行解析&#xff0c;从而生成发送给 Web 服务器的请求信息 URL? URL 实际上是请求服务器里的文件资源 当没有路径名时&#xff0c;就代表访问根目录下事先设置的默认文件&#xff0c;也就是 /index.html 或者 /default.html 这些文件…

计算机网络复习笔记(三)物理层

文章目录一物理层的基本概念四大特性&#xff1a;两种信号&#xff1a;调制和编码传输介质三大部分二物理层的基本通信技术四种信道复用技术数据的传输方式三OSI模型一物理层的基本概念 四大特性&#xff1a; 机械特性 接口是怎么样的 电气特性 用多少伏的电 功能特性 线路上…

linux基础之计算机基础

一、计算机基础 &#xff08;1) 计算机发展&#xff1a;电子管、晶体管、集成电路、大规模集成电路 &#xff08;2) 冯诺依曼体系&#xff1a;用二进制表示数据和指令&#xff1b; 存储程序控制&#xff0c;程序和数据预先存入存储器&#xff1b; 计算机系统5大部分&#xf…

Python 高级编程(文件操作)

文件&#xff1a;存储在某种长期存储设备上的数据&#xff01;&#xff01;包括&#xff08;硬板 u 盘 移动硬盘 光盘&#xff09; 计算机中临时的数据&#xff1a; 存储在内存中&#xff0c;一旦操作结束&#xff0c;内存中的空间就会被释放 文件&#xff08;特指普通文本&am…

R语言 4.2.2安装包下载及安装教程

[软件名称]:R语言 4.2.2 [软件大小]: 75.6 MB [安装环境]: Win11/Win10/Win7 [软件安装包下载]: https://pan.quark.cn/s/b6f604930d04 R语言软件的GUI界面比较的简陋,只有一个命令行窗口,且每次创建图片都会跳出一个新的窗口,比较的繁琐,我们可以安装RStudio,来更方便的操作R(…

ChatGPT +工业机器人/自动驾驶控制器的一些尝试

ChatGPT 的功能目前已扩展到机器人领域&#xff0c;可以用语言直观控制如机械臂、无人机、家庭辅助机器人等的多个平台。这会改变人机交互的未来形式吗&#xff1f; 你可曾想过用自己的话告诉机器人该做什么&#xff0c;就像对人说话那样&#xff1f; 比如说&#xff0c;只要告…

多个硬盘挂载到同一个目录

同一目录无法重复挂载&#xff0c;后挂载的会覆盖之前挂载的磁盘。但是现在需要将4块磁盘并行挂载&#xff0c;该如何操作呢&#xff1f; 将2块磁盘合并到一个逻辑卷 进行挂载。 基本知识 基本概念PV(Physical Volume)- 物理卷物理卷在逻辑卷管理中处于最底层&#xff0c;它可…

新能源锂电池行业除杂工艺介绍

近年来新能源汽车快速发展对锂电池的需求引发了人们对锂资源的高度关注。由于锂需求不断上升&#xff0c;全球锂资源越来越紧缺&#xff0c;而在生产含锂产品中会有大量废水、废渣。这些废水废渣含有丰富的锂&#xff0c;对其进行回收提锂具有极高的经济利益。在氟化锂生产中会…

文件操作介绍及C语言实现通讯录管理系统3.0最终版(文件操作版本)

文章目录1. 前言2. 文件操作2.1 什么是文件2.2 文件缓冲区2.3 文件指针2.4 文件的打开与关闭2.5 文件的顺序读写3. 优化通讯录3.1 保存通讯录3.2 加载通讯录4. 结尾1. 前言 上一篇文章我们学习了动态内存开辟的相关知识点&#xff0c;并用动态内存函数优化了我们的通讯录&…

【数据库连接,线程,ThreadLocal三者之间的关系】

一、数据库连接与线程的关系 在实际项目中&#xff0c;数据库连接是很宝贵的资源&#xff0c;以MySQL为例&#xff0c;一台MySQL服务器最大连接数默认是100, 最大可以达到16384。但现实中最多是到200&#xff0c;再多MySQL服务器就承受不住了。因为mysql连接用的是tcp协议&…

JAVA:常用API

一.什么是API&#xff1f; API&#xff08;Application Programming Interface&#xff09;&#xff1a;应用程序编程接口。 简单的来说&#xff1a;就是Java帮我们已经写好的方法&#xff0c;我们可以直接使用。 二.有哪些常用的API&#xff1f; Object、Objects、StringB…

二战华为成功上岸,准备了小半年,要个27k应该也算不上很高吧~

先说下我基本情况&#xff0c;本科不是计算机专业&#xff0c;现在是学通信&#xff0c;然后做图像处理&#xff0c;可能面试官看我不是科班出身没有问太多计算机相关的问题&#xff0c;因为第一次找工作&#xff0c;华为的游戏专场又是最早开始的&#xff0c;就投递了&#xf…

二,八,十,十六进制等常用进制详解

总目录 文章目录总目录一、常用进制1、进制基本信息2、各进制的表示形式二、进制转换原理1、其他进制转为十进制计算原理2、十进制转为其他进制计算原理3、二进制&#xff0c;八进制&#xff0c;十六进制之间的转换结语一、常用进制 1、进制基本信息 基数数码名称描述20 和 1…