React 設計模式是開發人員用來解決使用 React 建立應用程式時遇到的常見問題和挑戰的既定實踐和解決方案。這些模式封裝了針對重複出現的設計問題的可重複使用解決方案,從而提高了可維護性、可擴展性和效率。它們提供了一種結構化的方法來組織元件、管理狀態、處理資料流和最佳化效能。
請考慮以下 6 種 React 設計模式:
容器和呈現模式
HOC(高階元件)模式
複合元件模式
提供者模式(使用提供者進行資料管理)
狀態減速器模式
元件組成模式
在此模式中,容器元件負責管理資料和狀態邏輯。它們從外部來源獲取資料,在必要時對其進行操作,並將其作為 props 傳遞給展示元件。它們通常連接到外部服務、Redux 儲存或上下文提供者。
另一方面,展示元件僅專注於 UI 元素的展示。他們透過 props 從容器元件接收資料,並以視覺上吸引人的方式呈現它。展示元件通常是無狀態的功能元件或純元件,這使得它們更容易測試和重複使用。
讓我們考慮一個複雜的範例來說明這些模式:
假設我們正在建立一個社群媒體儀表板,用戶可以在其中查看朋友的貼文並與他們互動。以下是我們建立元件的方式:
容器元件(FriendFeedContainer):
該元件將負責從 API 獲取有關好友貼文的資料、處理任何必要的資料轉換以及管理提要的狀態。它將相關資料傳遞給展示元件。
import React, { useState, useEffect } from 'react';
import FriendFeed from './FriendFeed';
const FriendFeedContainer = () => {
const [friendPosts, setFriendPosts] = useState([]);
useEffect(() => {
// Fetch friend posts from API
const fetchFriendPosts = async () => {
const posts = await fetch('https://api.example.com/friend-posts');
const data = await posts.json();
setFriendPosts(data);
};
fetchFriendPosts();
}, []);
return <FriendFeed posts={friendPosts} />;
};
export default FriendFeedContainer;
展示元件(FriendFeed):
該元件將從其父容器元件 (FriendFeedContainer) 接收好友貼文資料作為 props,並以視覺上吸引人的方式呈現它們。
import React from 'react';
const FriendFeed = ({ posts }) => {
return (
<div>
<h2>Friend Feed</h2>
<ul>
{posts.map(post => (
<li key={post.id}>
<p>{post.content}</p>
<p>Posted by: {post.author}</p>
</li>
))}
</ul>
</div>
);
};
export default FriendFeed;
透過以這種方式建立我們的元件,我們將獲取資料和管理狀態的問題與 UI 渲染邏輯分開。這種分離使得我們的 React 應用程式在擴充時可以更輕鬆地進行測試、重複使用和維護。
高階元件 (HOC) 是 React 中的一種模式,可讓您跨多個元件重複使用元件邏輯。它們是接受元件並傳回具有附加功能的新元件的函數。
為了示範 HOC 在具有 React hook 的社群媒體儀表板範例中的使用,讓我們考慮一個場景,其中您有多個元件需要從 API 取得使用者資料。您可以建立一個 HOC 來處理資料獲取並將獲取的資料作為 props 傳遞給包裝的元件,而不是在每個元件中重複取得邏輯。
這是一個基本範例:
import React, { useState, useEffect } from 'react';
// Define a higher-order component for fetching user data
const withUserData = (WrappedComponent) => {
return (props) => {
const [userData, setUserData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate fetching user data from an API
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
setUserData(data);
setLoading(false);
} catch (error) {
console.error('Error fetching user data:', error);
setLoading(false);
}
};
fetchData();
}, []);
return (
<div>
{loading ? (
<p>Loading...</p>
) : (
<WrappedComponent {...props} userData={userData} />
)}
</div>
);
};
};
// Create a component to display user data
const UserProfile = ({ userData }) => {
return (
<div>
<h2>User Profile</h2>
{userData && (
<div>
<p>Name: {userData.name}</p>
<p>Email: {userData.email}</p>
{/* Additional user data fields */}
</div>
)}
</div>
);
};
// Wrap the UserProfile component with the withUserData HOC
const UserProfileWithUserData = withUserData(UserProfile);
// Main component where you can render the wrapped component
const SocialMediaDashboard = () => {
return (
<div>
<h1>Social Media Dashboard</h1>
<UserProfileWithUserData />
</div>
);
};
export default SocialMediaDashboard;
在這個例子中:
withUserData
是一個高階元件,用於處理從 API 取得使用者資料。它包裝傳遞的元件 ( WrappedComponent
) 並將取得的使用者資料作為 prop ( userData
) 提供給它。
UserProfile
是一個功能元件,它接收userData
屬性並顯示使用者設定檔資訊。
UserProfileWithUserData
是透過使用withUserData
包裝UserProfile
傳回的元件。
SocialMediaDashboard
是主要元件,您可以在其中呈現UserProfileWithUserData
或任何其他需要使用者資料的元件。
使用此模式,您可以輕鬆地跨社交媒體儀表板應用程式中的多個元件重複使用資料取得邏輯,而無需重複程式碼。
React 中的複合元件模式是一種設計模式,可讓您建立協同工作以形成有凝聚力的 UI 的元件,同時仍保持明確的關注點分離並提供自訂元件行為和外觀的靈活性。
在此模式中,父元件充當一個或多個子元件(稱為「複合元件」)的容器。這些子元件協同工作以實現特定的功能或行為。複合元件的關鍵特徵是它們透過父元件彼此共享狀態和功能。
以下是使用 hooks 在 React 中實作複合元件模式的簡單範例:
import React, { useState } from 'react';
// Parent component that holds the compound components
const Toggle = ({ children }) => {
const [isOn, setIsOn] = useState(false);
// Function to toggle the state
const toggle = () => {
setIsOn((prevIsOn) => !prevIsOn);
};
// Clone the children and pass the toggle function and state to them
const childrenWithProps = React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { isOn, toggle });
}
return child;
});
return <div>{childrenWithProps}</div>;
};
// Child component for the toggle button
const ToggleButton = ({ isOn, toggle }) => {
return (
<button onClick={toggle}>
{isOn ? 'Turn Off' : 'Turn On'}
</button>
);
};
// Child component for the toggle status
const ToggleStatus = ({ isOn }) => {
return <p>The toggle is {isOn ? 'on' : 'off'}.</p>;
};
// Main component where you use the compound components
const App = () => {
return (
<Toggle>
<ToggleStatus />
<ToggleButton />
</Toggle>
);
};
export default App;
在這個例子中:
Toggle
是保存複合元件( ToggleButton
和ToggleStatus
)的父元件。
ToggleButton
是負責渲染切換按鈕的子元件。
ToggleStatus
是另一個負責顯示切換狀態的子元件。
Toggle
元件管理狀態 ( isOn
) 並提供toggle
功能來控制狀態。它克隆其子級並將isOn
狀態和toggle
函數作為 props 傳遞給它們。
透過使用複合元件模式,您可以建立可重複使用和可組合的元件,封裝複雜的 UI 邏輯,同時仍允許自訂和靈活性。
React 中的提供者模式是一種設計模式,用於跨多個元件管理和共用應用程式狀態或資料。它涉及建立一個封裝狀態或資料的提供者元件,並透過 React 的上下文 API 將其提供給其後代元件。
讓我們透過一個範例來說明 React 中用於管理使用者身份驗證資料的 Provider 模式:
// UserContext.js
import React, { createContext, useState } from 'react';
// Create a context for user data
const UserContext = createContext();
// Provider component
export const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
// Function to login user
const login = (userData) => {
setUser(userData);
};
// Function to logout user
const logout = () => {
setUser(null);
};
return (
<UserContext.Provider value={{ user, login, logout }}>
{children}
</UserContext.Provider>
);
};
export default UserContext;
在這個例子中:
我們使用 React 的createContext
函數來建立一個名為UserContext
上下文。此上下文將用於跨元件共享用戶資料和與身份驗證相關的功能。
我們定義一個UserProvider
元件作為UserContext
的提供者。該元件使用useState
鉤子管理使用者狀態,並提供login
和logout
等方法來更新使用者狀態。
在UserProvider
內部,我們用UserContext.Provider
包裝children
,並將user
狀態以及login
和logout
函數作為提供者的值傳遞。
現在,任何需要存取使用者資料或驗證相關功能的元件都可以使用useContext
掛鉤來使用UserContext
。
讓我們建立一個使用上下文中的使用者資料的元件:
// UserProfile.js
import React, { useContext } from 'react';
import UserContext from './UserContext';
const UserProfile = () => {
const { user, logout } = useContext(UserContext);
return (
<div>
{user ? (
<div>
<h2>Welcome, {user.username}!</h2>
<button onClick={logout}>Logout</button>
</div>
) : (
<div>
<h2>Please log in</h2>
</div>
)}
</div>
);
};
export default UserProfile;
在此元件中:
我們匯入UserContext
並使用useContext
鉤子來存取UserProvider
提供的使用者資料和logout
功能。
根據使用者是否登錄,我們呈現不同的 UI 元素。
最後,我們用UserProvider
包裝我們的應用程式,以使用戶資料和身份驗證相關的功能可供所有元件使用:
// App.js
import React from 'react';
import { UserProvider } from './UserContext';
import UserProfile from './UserProfile';
const App = () => {
return (
<UserProvider>
<div>
<h1>My App</h1>
<UserProfile />
</div>
</UserProvider>
);
};
export default App;
透過這種方式,Provider 模式允許我們跨多個元件管理和共享應用程式狀態或資料,而無需進行 prop 鑽取,從而使我們的程式碼更乾淨、更易於維護。
原文出處:https://dev.to/fpaghar/react-component-design-patterns-part-1-5f0g