Javascript 如何将高阶组件连接到Redux存储?

Javascript 如何将高阶组件连接到Redux存储?,javascript,reactjs,redux,react-redux,higher-order-components,Javascript,Reactjs,Redux,React Redux,Higher Order Components,基本上,我有一个AuthenticationHOC,它必须获得redux状态,检查令牌是否存在,如果存在,则呈现包装的组件。如果没有,则发送一个操作以尝试从localStorage加载令牌。如果失败,请重定向到登录页面 import React from 'react'; import { connect } from 'react-redux'; import * as UserActions from '../../state/actions/user-actions'; import *

基本上,我有一个
AuthenticationHOC
,它必须获得redux状态,检查令牌是否存在,如果存在,则呈现包装的组件。如果没有,则发送一个操作以尝试从localStorage加载令牌。如果失败,请重定向到登录页面

import React from 'react';
import { connect } from 'react-redux';
import * as UserActions from '../../state/actions/user-actions';
import * as DashboardActions from '../../state/actions/dashboard-actions';

const mapStateToProps = state => {
  return {
    token: state.user.token,
    tried: state.user.triedLoadFromStorage,
  };
};

const _AuthenticationHOC = Component => props => {
  // if user is not logged and we 've not checked the localStorage
  if (!props.token && !props.tried) {
    // try load the data from local storage
      props.dispatch(DashboardActions.getDashboardFromStorage());
      props.dispatch(UserActions.getUserFromStorage());
  } else {
    // if the user has not token or we tried to load from localStorage 
    //without luck, then redirect to /login
    props.history.push('/login');
  }

  // if the user has token render the component
  return <Component />;
};

const AuthenticationHOC = connect(mapStateToProps)(_AuthenticationHOC);
export default AuthenticationHOC;
但我总是在上面的那行上打错标记

类型错误:对象(…)不是函数

然后我做了一个简化版本

我将代码从HOC替换为最简单的版本

const _AuthenticationHOC = Component => props => {
  return <Component {...props}/>;
};
const\u AuthenticationHOC=Component=>props=>{
返回;
};
这也不管用。然后我从我的HOC中删除了connect函数,只导出这个组件和tada。。。现在工作


所以我怀疑connect返回的对象不能用作HoC函数。这是正确的吗?我能在这里做什么?

正如您第一次尝试所描述的:
const SomeComponent=AuthenticationHOC(connect(mapstatetrops)(HomeComponent))

根据定义,这意味着将参数作为纯组件传递给
AuthenticationHOC
将返回另一个组件。但这里您传递的是另一个HOC,即
connect()
,它不是一个组件,而是一个包装器。因此根据定义,
return
解析为
return
将产生语法错误或运行时错误

将纯组件作为某些
HomeComponent
传递将起作用,因为它只是一个组件

我猜在幕后,
connect()
会。它所做的是返回一个组件包装器,并将其
MapStateTrops
mapDispatchToProps
作为插入的附加道具。来源-

如中所述:

connect()的返回是一个包装函数,它接受 组件并返回一个包装器组件及其附加的道具 注射

因此,我们可以将序列反转为:

const AuthenticationHOC = _AuthenticationHOC(HomeComponent);
export default connect(mapStateToProps)(AuthenticationHOC);
并确保在您的HOC中通过
道具

const _AuthenticationHOC = Component => props => {
  return <Component {...props} />; // pass props
};
const\u AuthenticationHOC=Component=>props=>{
return;//传递道具
};
请参阅此答案的底部,阅读对问题内容的直接回答。我将从我们在日常开发中使用的良好实践开始


连接 Redux提供了一个有用的方法

所有的
compose
功能都是让您编写深度嵌套的函数转换,而无需代码向右漂移

所以在这里,我们可以用它来嵌套HOC,但要可读

// Returns a new HoC (function taking a component as a parameter)
export default compose(
  // Parent HoC feeds the Auth HoC
  connect(({ user: { token, triedLoadFromStorage: tried } }) => ({
    token,
    tried
  })),

  // Your own HoC
  AuthenticationHOC
);
这类似于手动创建一个新的容器HoC函数

const mapState = ({ user: { token, triedLoadFromStorage: tried } }) => ({
    token,
    tried
});

export default WrappedComponent => connect(mapState)(
  AuthenticationHOC(WrappedComponent)
);
然后,您可以透明地使用auth HoC

import withAuth from '../AuthenticationHOC';
// ...
export default withAuth(ComponentNeedingAuth);
编写一个干净且可测试的HoC 为了将auth组件与存储和路由隔离开来,我们可以将其拆分为多个文件,每个文件都有自己的职责

- withAuth/
  - index.js           // Wiring and exporting (container component)
  - withAuth.jsx       // Defining the presentational logic
  - withAuth.test.jsx  // Testing the logic
我们将
withAuth.jsx
文件的重点放在渲染和逻辑上,而不管它来自何处

// withAuth/withAuth.jsx
import React from 'react';

export default Component => ({
  // Destructure props here, which filters them at the same time.
  tried,
  token,
  getDashboardFromStorage, 
  getUserFromStorage, 
  onUnauthenticated, 
  ...props
}) => {
  // if user is not logged and we 've not checked the localStorage
  if (!token && !tried) {
    // try load the data from local storage
    getDashboardFromStorage();
    getUserFromStorage();
  } else {
    // if the user has no token or we tried to load from localStorage
    onUnauthenticated();
  }

  // if the user has token render the component PASSING DOWN the props.
  return <Component {...props} />;
};
onUnauthenticated
作为存储操作的好处是,不同的还原程序现在可以对其作出反应,比如擦除用户数据、其仪表板数据等

测试HoC 然后,可以用authHoC测试
的隔离逻辑,比如and

在大多数情况下,将立即调用包装器函数,而无需 保存在临时变量中:

export default connect(mapState, mapDispatch)(Login)

然后我试着用这个

const SomeComponent = AuthenticationHOC(connect(mapStateToProps)(HomeComponent));
AuthenticationHOC(connect(mapStateToProps)(HomeComponent))
虽然连接HoCs的顺序是相反的,但您很接近。应该是:

connect(mapStateToProps)(AuthenticationHOC(HomeComponent))
通过这种方式,
AuthenticationHOC
从商店接收道具,并且
HomeComponent
被正确的HoC正确包装,它将返回一个新的有效组件

也就是说,我们可以做很多事情来改善这一点



一,。如果您不确定是否要将index.js文件用于容器组件,您可以根据自己的喜好对其进行重构,例如withAuthContainer.jsx文件,该文件可以在索引中导出,也可以让开发人员选择他们需要的文件。

感谢您的详细回答,从经验丰富的开发人员那里学习如何编写更好的代码总是很好的。
export default connect(mapState, mapDispatch)(Login)
AuthenticationHOC(connect(mapStateToProps)(HomeComponent))
connect(mapStateToProps)(AuthenticationHOC(HomeComponent))