首頁 > web前端 > js教程 > 停止犯這些組件錯誤

停止犯這些組件錯誤

DDD
發布: 2024-11-19 10:43:03
原創
935 人瀏覽過

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 />
      <OrderHistory />
      <NotificationCenter />
      <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 />
      <OrderHistory />
      <NotificationCenter />
      <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} />
        </Navigation>
      </Sidebar>
    </Layout>
  );
};
登入後複製
登入後複製

重點

上下文非常適合應用程式範圍的數據,例如使用者資訊、主題或全域設定。然而,它並不總是最好的選擇——不要過度使用它。對於局部狀態,考慮是否可以調整組件結構以避免完全鑽取。

目標是讓你的元件清晰且可維護。避免螺旋鑽探將為您節省時間、減少挫敗感並避免日後無數令人頭痛的問題。

過早的優化陷阱

您可能聽過關於過早優化是萬惡之源的名言。好吧,歡迎來到組件級邪惡。我說的是那些時候,我們甚至不知道是否需要兩次之前就嘗試讓所有東西都可重複使用。

通常是這樣的:

const UserContext = createContext();

const App = () => {
  const [user, setUser] = useState({});
  return (
    <UserContext.Provider value={user}>
      <Layout>
        <Sidebar>
          <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} />
      </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-${variant}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

// Create specific buttons when you actually need them
const LoadingButton = ({ isLoading, children, ...props }) => {
  return (
    <Button {...props}>
      {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 />
      <OrderHistory />
      <NotificationCenter />
      <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} />
        </Navigation>
      </Sidebar>
    </Layout>
  );
};
登入後複製
登入後複製

去抖動確保我們不會在每次按鍵時獲取數據,從而減少不必要的 API 呼叫和重新渲染。

快速效能提示

  • 不要過度使用記憶:僅在值得的時候進行最佳化。
  • 避免內嵌函數:穩定的引用可以提高效能。
  • 保持 props 可預測:淺且穩定的 props 有助於組件保持高效。
  • 分解大型清單:像react-window這樣的工具可以優雅地處理大資料集。
  • 將狀態移得更近:僅在實際需要的地方管理狀態。
  • 使用 DevTools 進行分析:最佳化前始終進行測量。

結論

建構元件並不是什麼複雜的事情,但說實話,我們很容易養成壞習慣。我犯過這些錯誤中的每一個(有時仍然會犯)。沒關係。重要的是儘早發現它們、修復它們並避免粗糙的程式碼庫。

更好組件的快速清單

✅ 單一職責:如果您無法用一句話概括組件的工作,那麼就該將其分解。

✅ 道具管理:層層傳遞道具?考慮使用上下文或利用組合來代替。

✅ 狀態與效果:集中效果,正確清理它們,並讓現代工具處理複雜的資料擷取。

✅ 效能:不要為了最佳化而最佳化-首先要衡量。在需要時巧妙地使用 memo、useMemo 和 useCallback 等工具。

✅ 從簡單開始:解決你現在遇到的問題,而不是將來可能遇到的問題。

最好的組件不是華而不實或過於聰明 - 它們是您的團隊可以在六個月內閱讀和維護的組件。

記住:這些不是硬性規則,只是指導方針。有時你會打破它們,那很好。我們的目標不是完美,而是建立一些組件,讓您在以後重新審視自己的職業選擇時不會產生疑問。

以上是停止犯這些組件錯誤的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板