通常来说,我认为情况并不算糟糕,熟练的手可以几乎做到一切。然而,最近我注意到一些事情改变了我对这个行业的看法。似乎在这些无尽的趋势、范式和新奇玩意中,我们忘记了前端开发的支柱(意思是忘记了基础知识,没有轮子没法写代码了)。
在这篇文章中,我想分享一些最近项目中的代码片段,并试着解释一下我的想法。不多说了,让我们开始吧!
文章目录
无休止的过度复杂化
来自1993年的错误
万恶之源
几个重要提示
无休止的过度复杂化
这里我们有最基本的卡片组件(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
非直接翻译,有自行改编和添加部分,翻译水平有限,难免有疏漏,欢迎指正