事實是,組件看似簡單。上手很簡單——定義一個函數,回傳一些 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 };
聽起來很熟悉嗎?
如果出現以下情況,您的組件可能已變成「一切組件」:
解決方案?不要使用單一的所有組件,而是將職責分解為更小的、更有針對性的部分。
// 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 } ); };
快速提示
讓我們來談談那些偷偷摸摸的效能問題。他們是那種在雷達下飛行的人,因為一切看起來都很好——直到事實並非如此。讓我們揭開這些無聲的罪魁禍首,看看如何解決它們。
問題
這是一個存在一些微妙性能缺陷的組件:
// 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 呼叫和重新渲染。
快速效能提示
建構元件並不是什麼複雜的事情,但說實話,我們很容易養成壞習慣。我犯過這些錯誤中的每一個(有時仍然會犯)。沒關係。重要的是儘早發現它們、修復它們並避免粗糙的程式碼庫。
更好組件的快速清單
✅ 單一職責:如果您無法用一句話概括組件的工作,那麼就該將其分解。
✅ 道具管理:層層傳遞道具?考慮使用上下文或利用組合來代替。
✅ 狀態與效果:集中效果,正確清理它們,並讓現代工具處理複雜的資料擷取。
✅ 效能:不要為了最佳化而最佳化-首先要衡量。在需要時巧妙地使用 memo、useMemo 和 useCallback 等工具。
✅ 從簡單開始:解決你現在遇到的問題,而不是將來可能遇到的問題。
最好的組件不是華而不實或過於聰明 - 它們是您的團隊可以在六個月內閱讀和維護的組件。
記住:這些不是硬性規則,只是指導方針。有時你會打破它們,那很好。我們的目標不是完美,而是建立一些組件,讓您在以後重新審視自己的職業選擇時不會產生疑問。
以上是停止犯這些組件錯誤的詳細內容。更多資訊請關注PHP中文網其他相關文章!