HOC - 功能组件

新手上路,请多包涵

我已经在我的 React 应用程序中创建 一个 HOC,并且它工作正常。但是我想知道是否有办法将 HOC 创建为功能组件(有或没有状态)???因为给定的示例是基于类的组件。

试图在网上找到同样的东西,但什么也找不到。不确定那是否可能?或者做正确的事?

任何线索将不胜感激:)

原文由 Mohammed Amir Ansari 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 638
2 个回答

当然,您可以创建一个功能性无状态组件,它接受组件作为输入并返回其他组件作为输出,例如;

  1. 您可以创建一个 PrivateRoute 组件,它接受一个 Component 作为 prop 值,并根据用户是否经过身份验证返回其他一些 Component。
  2. 如果用户未通过身份验证(从上下文存储中读取),那么您将用户重定向到登录页面 <Redirect to='/login'/> 否则您返回作为道具传递的组件并将其他道具发送到该组件 <Component {...props} />

应用程序.js

 const App = () => {
  return (
      <Switch>
        <PrivateRoute exact path='/' component={Home} />
        <Route exact path='/about' component={About} />
        <Route exact path='/login' component={Login} />
        <Route exact path='/register' component={Register} />
      </Switch>
  );
}

export default App;

PrivateRoute.jsx

 import React, { useContext , useEffect} from 'react';
import { Route, Redirect } from 'react-router-dom'
import AuthContext from '../../context/auth/authContext'

const PrivateRoute = ({ component: Component, ...rest }) => {
  const authContext = useContext(AuthContext)
  const { loadUser, isAuthenticated } = authContext
  useEffect(() => {
    loadUser()
    // eslint-disable-next-line
  }, [])
  if(isAuthenticated === null){
    return <></>
  }
  return (
    <Route {...rest} render={props =>
      !isAuthenticated ? (
        <Redirect to='/login'/>
      ) : (
        <Component {...props} />
      )
    }
    />
  );
};
export default PrivateRoute;

Higher Order Components不一定是类组件,它们的目的是将一个Component作为输入,按照某种逻辑返回一个组件作为输出。

原文由 onuriltan 发布,翻译遵循 CC BY-SA 4.0 许可协议

我同意 siraj ,严格来说, 接受的答案 中的示例不是真正的 HOC。 HOC 的显着特征是它 返回一个 component ,而接受答案中的 PrivateRoute 组件本身 就是 一个组件。因此,虽然它完成了它设定的目标,但我认为它不是 HOC 的一个很好的例子。

在功能组件世界中,最基本的 HOC 看起来像这样:

 const withNothing = Component => ({ ...props }) => (
  <Component {...props} />
);

调用 withNothing 返回另一个组件(不是实例,这是主要区别),然后可以像常规组件一样使用它:

 const ComponentWithNothing = withNothing(Component);
const instance = <ComponentWithNothing someProp="test" />;

使用此方法的一种方法是,如果您想使用临时(没有双关语, _哈哈_)上下文提供程序。

假设我的应用程序有多个用户可以登录的点。我不想在所有这些点上复制登录逻辑(API 调用和成功/错误消息),所以我想要一个可重用的 <Login /> 组件。然而,在我的例子中,所有这些登录点在视觉上都有很大不同,因此可重用组件不是一个选项。我需要的是一个可重用的 <WithLogin /> 组件,它将为其子组件提供所有必要的功能 - API 调用和成功/错误消息。这是执行此操作的一种方法:

 // This context will only hold the `login` method.
// Calling this method will invoke all the required logic.
const LoginContext = React.createContext();
LoginContext.displayName = "Login";

// This "HOC" (not a true HOC yet) should take care of
// all the reusable logic - API calls and messages.
// This will allow me to pass different layouts as children.
const WithLogin = ({ children }) => {
  const [popup, setPopup] = useState(null);

  const doLogin = useCallback(
    (email, password) =>
      callLoginAPI(email, password).then(
        () => {
          setPopup({
            message: "Success"
          });
        },
        () => {
          setPopup({
            error: true,
            message: "Failure"
          });
        }
      ),
    [setPopup]
  );

  return (
    <LoginContext.Provider value={doLogin}>
      {children}

      {popup ? (
        <Modal
          error={popup.error}
          message={popup.message}
          onClose={() => setPopup(null)}
        />
      ) : null}
    </LoginContext.Provider>
  );
};

// This is my main component. It is very neat and simple
// because all the technical bits are inside WithLogin.
const MyComponent = () => {
  const login = useContext(LoginContext);

  const doLogin = useCallback(() => {
    login("a@b.c", "password");
  }, [login]);

  return (
    <WithLogin>
      <button type="button" onClick={doLogin}>
        Login!
      </button>
    </WithLogin>
  );
};

不幸的是,这不起作用,因为 LoginContext.Provider MyComponent --- 中实例化,所以 useContext(LoginContext) 什么都不返回。

HOC 来救援!如果我添加一个小中间人怎么办:

 const withLogin = Component => ({ ...props }) => (
  <WithLogin>
    <Component {...props} />
  </WithLogin>
);

接着:

 const MyComponent = () => {
  const login = useContext(LoginContext);

  const doLogin = useCallback(() => {
    login("a@b.c", "password");
  }, [login]);

  return (
    <button type="button" onClick={doLogin}>
      Login!
    </button>
  );
};

const MyComponentWithLogin = withLogin(MyComponent);

砰! MyComponentWithLogin 现在将按预期工作。

这可能不是解决这种特殊情况的最佳方式,但我有点喜欢它。

是的,它真的只是一个额外的函数调用,仅此而已!根据官方指南:

HOC 本身并不是 React API 的一部分。它们是一种从 React 的组合性质中浮现出来的模式。

原文由 Avius 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题