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

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

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

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

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

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Linux新版
SublimeText3 Linux最新版