搜索
首页web前端js教程停止犯这些组件错误
停止犯这些组件错误Nov 19, 2024 am 10:43 AM

Stop Making These Component Mistakes

事实是,组件看似简单。上手很容易——定义一个函数,返回一些 JSX,然后就到此为止。但是要编写干净、可维护且易于使用的组件吗?这是一场完全不同的比赛。

在没有意识到的情况下,我们创建了以下组件:

  • 太大了,一眼看不懂。
  • 测试起来非常困难。
  • 耦合如此紧密,无法重用。
  • 由于糟糕的绩效决策而迟缓。

在这篇文章中,我将引导您了解开发人员在使用 React 组件时最常见的错误。更重要的是,我将向您展示如何在不破坏整个应用程序的情况下修复它们。

无论您是刚刚入门还是拥有多年的经验,这些技巧都将帮助您编写出不仅具有功能性而且易于维护的组件。

“一切组件”反模式

让我们来谈谈我们都犯过的经典错误:一切组件。您已经看到它了——它一开始很小而且天真无邪,可能是一个简单的表单或仪表板。快进一点,现在它正在管理状态、处理 API 调用、格式化数据,还可能为您冲泡早晨咖啡。

// Please, no more of this
const UserDashboard = () => {
  const [userData, setUserData] = useState(null);
  const [orders, setOrders] = useState([]);
  const [notifications, setNotifications] = useState([]);
  const [settings, setSettings] = useState({});
  const [isEditing, setIsEditing] = useState(false);
  const [activeTab, setActiveTab] = useState('profile');

  // 15 separate useEffects
  // 10 different event handlers
  // Multiple conditional renders
  // 300+ lines of chaos
};

听起来很熟悉吗?

如何判断你是否有罪

如果出现以下情况,您的组件可能已变成“一切组件”:

  • 状态过载:您正在跟踪超过 3-4 个独立的状态。
  • 无休止的滚动:你花了太多时间寻找特定的功能或逻辑。
  • 依赖项膨胀: 你的 useEffect 依赖项看起来就像你的每周购物清单。
  • 否认功能蔓延:你不断告诉自己,多一个功能不会有什么坏处。

分解它

解决方案?不要使用单一的所有组件,而是将职责分解为更小的、更有针对性的部分。

// A cleaner, smarter approach
const UserDashboard = () => {
  return (
    <div>
      <userprofile></userprofile>
      <orderhistory></orderhistory>
      <notificationcenter></notificationcenter>
      <usersettings></usersettings>
    </div>
  );
};

关键原则:逻辑>布局

重构时,不要根据组件在屏幕上的外观来破坏它们。按责任划分他们。问问自己:这个功能是否值得拥有自己的组件?如果它正在处理一些不同的东西——比如用户个人资料或订单历史记录——它可能会这样做。

提示: 一个好的组件只做一件事并且做得很好。如果您很难用一句话描述它的目的,那么它很可能试图做太多事情。

螺旋桨钻井地狱

我们来讨论一下不太好玩的“传递道具”游戏。如果您曾将同一个 prop 通过多个组件传递给一个深度嵌套的子组件,那么您就陷入了 prop 钻探地狱。

// Please, no more of this
const UserDashboard = () => {
  const [userData, setUserData] = useState(null);
  const [orders, setOrders] = useState([]);
  const [notifications, setNotifications] = useState([]);
  const [settings, setSettings] = useState({});
  const [isEditing, setIsEditing] = useState(false);
  const [activeTab, setActiveTab] = useState('profile');

  // 15 separate useEffects
  // 10 different event handlers
  // Multiple conditional renders
  // 300+ lines of chaos
};

这种方法不仅令人烦恼,而且还会造成长期问题。想象一下需要重命名 user 属性。突然,您在五个或更多地方更新它。更糟糕的是,您最终将组件与它们甚至不使用的数据绑定在一起。

如何解决这个问题

没有必要用你的道具来玩烫手山芋。这里有两个实用的解决方案,可以完全避免钻孔。

1。使用共享数据的上下文

如果跨应用程序的不同部分访问一段数据,React 的 Context API 可以简化事情。

// A cleaner, smarter approach
const UserDashboard = () => {
  return (
    <div>
      <userprofile></userprofile>
      <orderhistory></orderhistory>
      <notificationcenter></notificationcenter>
      <usersettings></usersettings>
    </div>
  );
};

2。使用组合来提高灵活性

不要通过层强制道具,而是重组组件,以便它们只传递需要的内容。

// This is exhausting
const App = () => {
  const [user, setUser] = useState({});
  return (
    <layout user="{user}">
      <sidebar user="{user}">
        <navigation user="{user}">
          <usermenu user="{user}"></usermenu>
        </navigation>
      </sidebar>
    </layout>
  );
};

要点

上下文非常适合应用程序范围的数据,例如用户信息、主题或全局设置。然而,它并不总是最好的选择——不要过度使用它。对于局部状态,考虑是否可以调整组件结构以避免完全钻取。

目标是让你的组件清晰且可维护。避免螺旋钻探将为您节省时间、减少挫败感并避免日后无数令人头疼的问题。

过早的优化陷阱

您可能听说过关于过早优化是万恶之源的名言。好吧,欢迎来到组件级邪恶。我说的是那些时候,我们甚至不知道是否需要两次之前就尝试让所有东西都可重复使用。

通常是这样的:

const UserContext = createContext();

const App = () => {
  const [user, setUser] = useState({});
  return (
    <usercontext.provider value="{user}">
      <layout>
        <sidebar>
          <navigation></navigation>
        </sidebar>
      </layout>
    </usercontext.provider>
  );
};

// Use it only where needed
const UserMenu = () => {
  const user = useContext(UserContext);
  return <div>{user.name}</div>;
};

让你的组件自然发展。为您知道您今天需要的东西而构建。如果出现新的需求,请在可以清楚地证明其合理性的情况下添加功能。过早的优化会浪费时间,增加复杂性,而且很少有回报。

记住: YAGNI 原则(你不会需要它)也适用于组件。当你真正遇到了他们正在解决的问题时,最好的抽象就会出现。过度设计可能会让人感觉很主动,但简单总是胜出。

副作用管理不善

这是不良效果管理的经典示例。看起来很眼熟吗?

// Focused components for better clarity
const Navigation = ({ children }) => {
  return <nav>{children}</nav>;
};

// Pass data only where required
const App = () => {
  const user = useUser();
  return (
    <layout>
      <navigation>
        <usermenu user="{user}"></usermenu>
      </navigation>
    </layout>
  );
};

常见错误和修复

1) 混乱的数据获取

糟糕的数据处理产生的错误比它解决的错误还要多。这是一种更简洁的方法:

// Behold, the over-engineered button
const Button = ({ 
  children,
  variant = 'primary',
  size = 'medium',
  isFullWidth = false,
  isDisabled = false,
  isLoading = false,
  leftIcon,
  rightIcon,
  onClick,
  customClassName,
  style,
  loadingText = 'Loading...',
  tooltipText,
  animationType,
  // ... 10 more props
}) => {
  // 50 lines of prop processing logic
  return (
    <button classname="{generateComplexClassNames()}">



<h3>
  
  
  Why This Hurts
</h3>

<ul>
<li>Your “simple” button now requires an instruction manual.</li>
<li>Most of those 15+ props will never be used.</li>
<li>Making updates becomes risky because you have to account for endless combinations.</li>
<li>Writing tests becomes painful, with a hundred possible scenarios to consider.</li>
</ul>

<h3>
  
  
  Better Approach:
</h3>

<p>Instead of building for every imaginable scenario, start small and let your components grow as needed.<br>
</p>

<pre class="brush:php;toolbar:false">// Start simple
const Button = ({ children, onClick, variant = 'primary' }) => {
  return (
    <button classname="{`btn" btn- onclick="{onClick}">
      {children}
    </button>
  );
}

// Create specific buttons when you actually need them
const LoadingButton = ({ isLoading, children, ...props }) => {
  return (
    <button>
      {isLoading ? 'Loading...' : children}
    </button>
  );
}

2)忘记清理

总是清理干净自己:

const UserProfile = ({ userId }) => {  
  const [user, setUser] = useState(null);  
  const [posts, setPosts] = useState([]);  

  // Dependency array woes
  useEffect(() => {  
    fetchUserData(userId);  
    fetchUserPosts(userId);  
    // No cleanup? Yikes.
  }, []); // eslint-disable-line react-hooks/exhaustive-deps  

  // Multiple effects, all tangled
  useEffect(() => {  
    const subscription = subscribeToUserStatus(userId);  
  }, [userId]);  

  // Cleanup? What cleanup?
  useEffect(() => {  
    const interval = setInterval(checkNotifications, 5000);  
  }, []);  
};

3) 忽略竞争条件

使用此技术避免重叠请求:

// Improved version
const UserProfile = ({ userId }) => {  
  const { data: user, isLoading } = useQuery(  
    ['user', userId],  
    () => fetchUserData(userId)  
  );  

  // Keep concerns separate
  const { data: posts } = useQuery(  
    ['posts', userId],  
    () => fetchUserPosts(userId),  
    { enabled: !!user }  
  );  
};

快速提示

  • 使用 useEffect 之前请三思:有时候,你可能根本不需要它。
  • 保持专注:一种效果应该承担一种责任。
  • 始终清理:订阅、间隔和事件监听器需要关注。
  • 使用正确的工具:像 React Query 这样的库可以简化数据获取和缓存。
  • 不要用 eslint-disable 作弊:修复依赖问题而不是隐藏它们。

性能盲点

让我们来谈谈那些偷偷摸摸的性能问题。他们是那种在雷达下飞行的人,因为一切看起来都很好——直到事实并非如此。让我们揭开这些无声的罪魁祸首,看看如何解决它们。

问题

这是一个存在一些微妙性能缺陷的组件:

// Please, no more of this
const UserDashboard = () => {
  const [userData, setUserData] = useState(null);
  const [orders, setOrders] = useState([]);
  const [notifications, setNotifications] = useState([]);
  const [settings, setSettings] = useState({});
  const [isEditing, setIsEditing] = useState(false);
  const [activeTab, setActiveTab] = useState('profile');

  // 15 separate useEffects
  // 10 different event handlers
  // Multiple conditional renders
  // 300+ lines of chaos
};

你能发现问题吗?让我们把它们分解一下。

修复

1) 记住昂贵的计算

不要在每次渲染时重新计算所有内容,而是使用 useMemo 来缓存结果:

// A cleaner, smarter approach
const UserDashboard = () => {
  return (
    <div>
      <userprofile></userprofile>
      <orderhistory></orderhistory>
      <notificationcenter></notificationcenter>
      <usersettings></usersettings>
    </div>
  );
};

这避免了在每次渲染时重新计算数据并重新创建事件处理程序。它还可以防止带有备忘录的子组件不必要的重新渲染。

2) 高效的状态更新

糟糕的状态管理也会降低性能。这是处理搜索结果等更新的更好方法:

// This is exhausting
const App = () => {
  const [user, setUser] = useState({});
  return (
    <layout user="{user}">
      <sidebar user="{user}">
        <navigation user="{user}">
          <usermenu user="{user}"></usermenu>
        </navigation>
      </sidebar>
    </layout>
  );
};

去抖动确保我们不会在每次击键时获取数据,从而减少不必要的 API 调用和重新渲染。

快速性能提示

  • 不要过度使用记忆:仅在值得的时候进行优化。
  • 避免内联函数:稳定的引用可以提高性能。
  • 保持 props 可预测:浅且稳定的 props 有助于组件保持高效。
  • 分解大型列表:像react-window这样的工具可以优雅地处理大数据集。
  • 将状态移得更近:仅在实际需要的地方管理状态。
  • 使用 DevTools 进行分析:优化前始终进行测量。

结论

构建组件并不是什么复杂的事情,但说实话,我们很容易养成坏习惯。我犯过这些错误中的每一个(有时仍然会犯)。没关系。重要的是尽早发现它们、修复它们并避免粗糙的代码库。

更好组件的快速清单

✅ 单一职责:如果您无法用一句话概括组件的工作,那么就该将其分解。

✅ 道具管理:层层传递道具?考虑使用上下文或利用组合来代替。

✅ 状态和效果:集中效果,正确清理它们,并让现代工具处理复杂的数据获取。

✅ 性能:不要为了优化而优化——首先要衡量。在需要时巧妙地使用 memo、useMemo 和 useCallback 等工具。

✅ 从简单开始:解决你现在遇到的问题,而不是将来可能遇到的问题。

最好的组件不是华而不实或过于聪明 - 它们是您的团队可以在六个月内阅读和维护的组件。

记住:这些不是硬性规则,只是指导方针。有时你会打破它们,那很好。我们的目标不是完美,而是构建一些组件,让您在以后重新审视自己的职业选择时不会产生疑问。

以上是停止犯这些组件错误的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
在JavaScript中替换字符串字符在JavaScript中替换字符串字符Mar 11, 2025 am 12:07 AM

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

构建您自己的Ajax Web应用程序构建您自己的Ajax Web应用程序Mar 09, 2025 am 12:11 AM

因此,在这里,您准备好了解所有称为Ajax的东西。但是,到底是什么? AJAX一词是指用于创建动态,交互式Web内容的一系列宽松的技术。 Ajax一词,最初由Jesse J创造

如何创建和发布自己的JavaScript库?如何创建和发布自己的JavaScript库?Mar 18, 2025 pm 03:12 PM

文章讨论了创建,发布和维护JavaScript库,专注于计划,开发,测试,文档和促销策略。

如何在浏览器中优化JavaScript代码以进行性能?如何在浏览器中优化JavaScript代码以进行性能?Mar 18, 2025 pm 03:14 PM

本文讨论了在浏览器中优化JavaScript性能的策略,重点是减少执行时间并最大程度地减少对页面负载速度的影响。

如何使用浏览器开发人员工具有效调试JavaScript代码?如何使用浏览器开发人员工具有效调试JavaScript代码?Mar 18, 2025 pm 03:16 PM

本文讨论了使用浏览器开发人员工具的有效JavaScript调试,专注于设置断点,使用控制台和分析性能。

如何构建简单的jQuery滑块如何构建简单的jQuery滑块Mar 11, 2025 am 12:19 AM

本文将引导您使用jQuery库创建一个简单的图片轮播。我们将使用bxSlider库,它基于jQuery构建,并提供许多配置选项来设置轮播。 如今,图片轮播已成为网站必备功能——一图胜千言! 决定使用图片轮播后,下一个问题是如何创建它。首先,您需要收集高质量、高分辨率的图片。 接下来,您需要使用HTML和一些JavaScript代码来创建图片轮播。网络上有很多库可以帮助您以不同的方式创建轮播。我们将使用开源的bxSlider库。 bxSlider库支持响应式设计,因此使用此库构建的轮播可以适应任何

jQuery矩阵效果jQuery矩阵效果Mar 10, 2025 am 12:52 AM

将矩阵电影特效带入你的网页!这是一个基于著名电影《黑客帝国》的酷炫jQuery插件。该插件模拟了电影中经典的绿色字符特效,只需选择一张图片,插件就会将其转换为充满数字字符的矩阵风格画面。快来试试吧,非常有趣! 工作原理 插件将图片加载到画布上,读取像素和颜色值: data = ctx.getImageData(x, y, settings.grainSize, settings.grainSize).data 插件巧妙地读取图片的矩形区域,并利用jQuery计算每个区域的平均颜色。然后,使用

如何使用源地图调试缩小JavaScript代码?如何使用源地图调试缩小JavaScript代码?Mar 18, 2025 pm 03:17 PM

本文说明了如何使用源地图通过将其映射回原始代码来调试JAVASCRIPT。它讨论了启用源地图,设置断点以及使用Chrome DevTools和WebPack之类的工具。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。