React 面试设计模式

探索 React 设计模式,包括高阶组件、渲染道具和容器/展示模式,帮助您构建干净、可重用和可扩展的应用程序

作者
Ex-Meta Staff Engineer

React 鼓励基于组件的架构,但随着应用程序的增长,维护干净、可重用和可扩展的代码至关重要。以下是 React 中一些最常见的设计模式以及何时使用它们。

高阶组件 (HOC)

高阶组件 (HOC) 是一个接受组件并返回一个增强组件的函数,该组件具有额外的 props 或逻辑。它促进了跨多个组件的代码重用。

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 已经不再那么普遍。

在 react.dev 上进一步阅读:高阶组件 – React

渲染道具

渲染道具涉及将一个渲染元素的函数作为 prop 传递给一个组件。该组件使用某些参数(通常是其自身的状态)调用该 prop。

这允许组件的父级根据组件状态进行渲染,同时仍然允许父级从外部自定义行为/外观。

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.dev 上进一步阅读:渲染道具 - React

容器/展示模式

容器/展示模式是 React 中使用的一种设计模式,用于将状态管理(逻辑)与 UI 渲染(展示)分开。它通过确保关注点的明确分离,有助于使组件可重用、可维护和可测试。

在客户端,数据可以来自用户的输入、从 API 获取、localStorage、WebSockets 等。不假设数据来自哪里是构建组件的好方法。

展示组件:

  • 仅专注于渲染 UI
  • 不包含状态(除了本地 UI 状态,如切换)
  • 通过 props 接收所有数据并使用事件处理程序(例如 onClickonChange
  • 可重用且易于测试,因为它们独立于业务逻辑
  • 不假定如何获取数据
function UserList({ users }) {
return (
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
);
}

容器组件:

  • 管理状态、API 调用和业务逻辑
  • 将数据和函数作为 props 传递给展示组件
  • 不包含 UI 代码(最小 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 上进一步阅读:容器/展示模式

面试需要了解的内容

  • 首先使用钩子:虽然 HOC 和 render props 曾经是 React 中代码重用的流行模式,但它们已被钩子取代。但是,它们在某些情况下仍然有用,在某些情况下,仅靠钩子可能不够用或不可用,例如在仍在使用类组件的旧代码库中。
  • 容器/展示超越前端:容器/展示模式背后的关键思想是将展示与数据源分离。将数据获取与展示分离是一个强大的概念,在前端工程之外也很有用。在构建后端系统时,可以从其他服务获取数据,从数据库加载数据,从文件系统读取数据等。通过进行这种分离,代码将更容易重用和测试。

练习题

测验: