上下文,Redux 还是 Composition?

这篇文章最初于 2023 年 2 月 23 日在我的博客页面上发布

我是受最近科技公司裁员影响的开发人员之一。因此,我开始用 React 参加前端职位的面试。

在一家公司,我被分配了一个经典的 React 中的 prop 钻孔问题,

并被要求解决它。为了简单起见,给出的问题如下

这:

export default function App() {
  const [user, setUser] = React.useState(null);

  const handleLogin = () => setUser(userDetails);

  return (
    
Company Logo
{user ? ( ) : ( )}
); } function Dashboard({ user }) { return (
); } function DashboardNav({ user }) { return (
); } function WelcomeUser({ user }) { return
Welcome {user.name}
; } function UserRole({ user }) { return
Role {user.role}
; }

正如你所看到的,我们将 user 属性从 App 组件传递给

子组件 `WelcomeUser` 和 `UserRole`。中间组件 `Dashboard` 和 `DashboardNav` 只是转发 props,并没有真正使用它。

Components using user property

这是 React 中的一个经典的 **prop 钻孔** 问题。

有趣的是,面试官要求使用 React Context API 来解决问题

或者使用 Redux。

通过 React Context 解决

使用上下文 API 来解决这个问题看起来就像下面的代码。

const UserContext = React.createContext(undefined);

export default function App() {
  const [user, setUser] = React.useState(null);

  const handleLogin = () => setUser(userDetails);

  return (
    
Company Logo: Context
{user ? ( ) : ( )}
); } function Dashboard() { return (
); } function DashboardNav() { return (
); } function WelcomeUser() { const user = React.useContext(UserContext); return
Welcome {user.name}
; } function UserRole() { const user = React.useContext(UserContext); return
Role {user.role}
; }

我们正在创建“UserContext”并使用提供程序包装仪表板,以便

我们可以将所需的 props 传递给深层嵌套的子组件。此解决方案

作品。

Components using user property with React Context

通过 Redux 解决

因此,如果我们采用经典的 redux 路线,我们需要创建一个类似的

结构并用一个全局存储包装所有内容,其中包含“用户”

目的。

解决方案代码将包含大量样板代码,因为我们使用“redux”来

解决一个简单的问题。

我只是给出了以下代码的要点,但如果你真的想探索完整的

代码,给你:用 redux 解决。

export default function App() {
  return (
    
      
    
  );
}

function ReduxApp({ user, setUser }) {
  const handleLogin = () => setUser(userDetails);

  return (
    
Company Logo: Redux
{user ? : }
); } function Dashboard() { return (
); } function DashboardNav() { return (
); } function WelcomeUser({ user }) { return
Welcome {user.name}
; } const mapStateToPropsWelcomeUser = (state) => ({ user: state }); const ConnectedWelcomeUser = connect(mapStateToPropsWelcomeUser)(WelcomeUser); function UserRole({ user }) { return
Role {user.role}
; } const mapStateToPropsUserRole = (state) => ({ user: state }); const ConnectedUserRole = connect(mapStateToPropsUserRole)(UserRole);

我们已经连接了需要访问全局状态的组件

存储在 redux 中。

我如何解决它

在阅读了关于 React Composition 的内容后,我通过以下方式解决了这个问题:

使用 `children` 属性,如下所示

export default function AppSolution() {
  const [user, setUser] = React.useState(null);

  const handleLogin = () => setUser(userDetails);

  return (
    
Company Logo
{user ? ( ) : ( )}
); } function Dashboard({ children }) { return
{children}
; } function DashboardNav({ children }) { return
{children}
; } function WelcomeUser({ user }) { return
Welcome {user.name}
; } function UserRole({ user }) { return
Role {user.role}
; }

如果你仔细想想,这就是解决这个问题的简单方法,而不需要引入

没有任何复杂性,例如`createContext`或`react-redux`。我们还获得了其他好处,例如

作为

  • 将来,如果我们在 Dashboard 内部引入任何状态并对其进行操作,我们的 DashboardNav 就不会重新渲染。
  • 通过仅向所需的组件提供道具,我们可以很好地了解用户的所有消费者,而无需在组件(文件)之间导航来寻找它们。
  • 这种模式并不新鲜,而且已经在 React 社区中被讨论过了。一个很好的演练是使用 React 中的 Composition 来避免“Prop Drilling”

    结论

    然而,我收到了面试官的反馈,内容如下

    受访者未能正确理解问题,无法提供预期的解决方案。

    我猜原因是面试官没有意识到这种模式,或者我选择了一种未被要求的方式解决问题。

    话虽如此,我现在有动力写更多关于 React 中有趣模式的文章,希望它能够覆盖更广泛的受众。

    通过分享这篇文章让我知道您的想法。

    参考

  • Codesandbox 解决方案
  • 使用 context 之前 - React Docs
  • 在 React 中使用 Composition 来避免“Prop Drilling”
  • 博客解答:React 渲染行为 (基本) 完整指南
  • 博客解答:为什么 React Context 不是一个“状态管理”工具(以及为什么它不能取代 Redux)