front-end-interview-handbook/packages/react-interview-playbook/contents/react-design-patterns/zh-CN.mdx

151 lines
5.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: React 面试设计模式
description: 探索 React 设计模式,包括高阶组件、渲染道具和容器/展示模式,帮助您构建干净、可重用和可扩展的应用程序
---
React 鼓励基于组件的架构,但随着应用程序的增长,维护干净、可重用和可扩展的代码至关重要。以下是 React 中一些最常见的设计模式以及何时使用它们。
## 高阶组件 (HOC)
高阶组件 (HOC) 是一个接受组件并返回一个增强组件的函数,该组件具有额外的 props 或逻辑。它促进了跨多个组件的代码重用。
```jsx
function withAuth(Component) {
return function WrappedComponent(props) {
const isAuthenticated = localStorage.getItem('token'); // 检查身份验证状态
return isAuthenticated ? <Component {...props} /> : <p>访问被拒绝</p>;
};
}
function Dashboard() {
return <h1>Dashboard</h1>;
}
const ProtectedDashboard = withAuth(Dashboard);
```
HOC 适用于:
* 在多个组件之间重用逻辑(例如,身份验证、分析、日志记录、获取数据)
* 在不修改原始组件的情况下添加行为
* 无法使用钩子的情况,例如类组件
高阶组件在 pre-hooks 时代对于向组件添加功能更有用。现在我们有了 React 钩子以及创建自定义钩子的能力HOC 已经不再那么普遍。
## 渲染道具
渲染道具涉及将一个渲染元素的函数作为 prop 传递给一个组件。该组件使用某些参数(通常是其自身的状态)调用该 prop。
这允许组件的父级根据组件状态进行渲染,同时仍然允许父级从外部自定义行为/外观。
```jsx
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMouseMove = (event) => {
setPosition({ x: event.clientX, y: event.clientY });
};
window.addEventListener('mousemove', handleMouseMove);
return () => window.removeEventListener('mousemove', handleMouseMove);
}, []);
return render(position);
}
function App() {
return (
<MouseTracker
render={(position) => (
<p>
Mouse: {position.x}, {position.y}
</p>
)}
/>
);
}
```
渲染道具适用于:
* 在组件之间共享逻辑,同时保持 UI 灵活性
* 无法使用钩子的情况,例如类组件
* 提供逻辑和行为的无头组件,同时允许自定义外观
## 容器/展示模式
容器/展示模式是 React 中使用的一种设计模式,用于将状态管理(逻辑)与 UI 渲染(展示)分开。它通过确保关注点的明确分离,有助于使组件可重用、可维护和可测试。
在客户端,数据可以来自用户的输入、从 API 获取、`localStorage`、WebSockets 等。不假设数据来自哪里是构建组件的好方法。
**展示组件:**
* 仅专注于渲染 UI
* 不包含状态(除了本地 UI 状态,如切换)
* 通过 props 接收所有数据并使用事件处理程序(例如 `onClick`、`onChange`
* 可重用且易于测试,因为它们独立于业务逻辑
* 不假定如何获取数据
```jsx
function UserList({ users }) {
return (
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
);
}
```
**容器组件:**
* 管理状态、API 调用和业务逻辑
* 将数据和函数作为 props 传递给展示组件
* 不包含 UI 代码(最小 JSX除了包装展示组件
```jsx
function UserListContainer() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json())
.then((data) => setUsers(data));
}, []);
return <UserList users={users} />;
}
```
这种模式允许:
* 使用不同的数据源重用 UI 组件
* UI 和状态逻辑之间的清晰分离
* 使 UI 组件更易于测试
### 替代方法
* **自定义钩子(例如,用于获取用户的 `useUser` 钩子)**:一种更现代的方法,可在多个组件中保持逻辑的可重用性
* **状态管理库Redux、Zustand**:单独处理全局状态,无需显式容器组件
在 react.dev 上进一步阅读:[容器/展示模式](https://www.patterns.dev/react/presentational-container-pattern)
## 面试需要了解的内容
* **首先使用钩子**:虽然 HOC 和 render props 曾经是 React 中代码重用的流行模式,但它们已被钩子取代。但是,它们在某些情况下仍然有用,在某些情况下,仅靠钩子可能不够用或不可用,例如在仍在使用类组件的旧代码库中。
* **容器/展示超越前端**:容器/展示模式背后的关键思想是将展示与数据源分离。将数据获取与展示分离是一个强大的概念,在前端工程之外也很有用。在构建后端系统时,可以从其他服务获取数据,从数据库加载数据,从文件系统读取数据等。通过进行这种分离,代码将更容易重用和测试。
## 练习题
**测验:**
* [React 中的高阶组件是什么?](/questions/quiz/what-are-higher-order-components-in-react?framework=react\&tab=quiz)
* [Flux 模式是什么,它有什么好处?](/questions/quiz/what-is-the-flux-pattern-and-what-are-its-benefits?framework=react\&tab=quiz)
* [解释 React 中的展示组件与容器组件模式](/questions/quiz/explain-the-presentational-vs-container-component-pattern-in-react?framework=react\&tab=quiz)
* [React 中的 render props 是什么,它们是做什么的?](/questions/quiz/what-are-render-props-in-react-and-what-are-they-for?framework=react\&tab=quiz)
* [解释 React 中的组合模式](/questions/quiz/explain-the-composition-pattern-in-react?framework=react\&tab=quiz)