停止犯這些組件錯誤
事實是,組件看似簡單。上手很簡單——定義一個函數,回傳一些 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中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python和JavaScript開發者的薪資沒有絕對的高低,具體取決於技能和行業需求。 1.Python在數據科學和機器學習領域可能薪資更高。 2.JavaScript在前端和全棧開發中需求大,薪資也可觀。 3.影響因素包括經驗、地理位置、公司規模和特定技能。

實現視差滾動和元素動畫效果的探討本文將探討如何實現類似資生堂官網(https://www.shiseido.co.jp/sb/wonderland/)中�...

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

如何在JavaScript中將具有相同ID的數組元素合併到一個對像中?在處理數據時,我們常常會遇到需要將具有相同ID�...

探索前端中類似VSCode的面板拖拽調整功能的實現在前端開發中,如何實現類似於VSCode...

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。
