Reactjs 是否可以创建一个React Hook工厂函数?

Reactjs 是否可以创建一个React Hook工厂函数?,reactjs,react-redux,react-hooks,Reactjs,React Redux,React Hooks,我有一个React应用程序,它严重依赖于redux、React-redux、以及redux传奇。我开始尝试React钩子,React redux中的useSelector和useDispatch钩子,我遇到了一个问题,就是如何编写一个工厂函数来为我的每个redux节点生成钩子 通常,我的应用程序使用的每个API端点都有一个redux节点。这个应用程序中大约有100个唯一的端点,因此大约有100个redux节点。然后,这些节点中的每一个都对应于一个状态-[node].js文件,如状态用户.js,等

我有一个React应用程序,它严重依赖于
redux
React-redux
、以及
redux传奇。我开始尝试React钩子,
React redux
中的
useSelector
useDispatch
钩子,我遇到了一个问题,就是如何编写一个工厂函数来为我的每个redux节点生成钩子

通常,我的应用程序使用的每个API端点都有一个redux节点。这个应用程序中大约有100个唯一的端点,因此大约有100个redux节点。然后,这些节点中的每一个都对应于一个
状态-[node].js
文件,如
状态用户.js
,等等。这些状态文件都封装了它们应该调用的端点,触发saga以处理HTTP生命周期(启动、失败、成功等)

随着时间的推移,我已经编写了代码,将大部分样板文件抽象为实用函数,包括自动生成动作创建者、选择器、还原器的函数,以及
connect
函数。这是一堆代码,有点复杂,但要点是这样的。首先,我设置了一个对象数组,用于描述此redux节点可能执行的操作。简化版本如下所示:

const messages = [
  { action: 'GET', creator: 'get', connect: true },
  { action: 'POST', creator: 'post', connect: true },
  { action: 'CLEAR', creator: 'clear', connect: true },
];
const { connector } = stateGenerators({
   keyword: 'users', //redux node keyword
   messages: messages,
   selectorKeys: selectorKeys

}) 
import { connector } from 'state-users';

class Users extends Component {
    componentDidMount() {
       this.props.get();
    }
    componentWillUnmount() {
      this.props.clear();
    }
    render () {
      const { data } = this.props;
      return (
        <div>
        {data.map()}
        </div>

      )
    }
}

export connector()(Users)
export const useReduxState = ({ id, defaultValues }) => {
  const selectors = useReduxListCommonSelectors({
    keyword:'users'
  });

  return {
    ...selectors,

  };
};
这说明将有三个操作,
get
post
clear
,它们应暴露在连接器中。我有一组常见的减缩器(例如,大多数
get
减缩器在节点之间是相同的),因此这里根据名称假设这些减缩器

然后我设置了一个选择器列表,如下所示:
const selectorKeys=['data','pending','errors']

…然后我有一个工厂函数,我将这些数组输入其中,它看起来像这样:

const messages = [
  { action: 'GET', creator: 'get', connect: true },
  { action: 'POST', creator: 'post', connect: true },
  { action: 'CLEAR', creator: 'clear', connect: true },
];
const { connector } = stateGenerators({
   keyword: 'users', //redux node keyword
   messages: messages,
   selectorKeys: selectorKeys

}) 
import { connector } from 'state-users';

class Users extends Component {
    componentDidMount() {
       this.props.get();
    }
    componentWillUnmount() {
      this.props.clear();
    }
    render () {
      const { data } = this.props;
      return (
        <div>
        {data.map()}
        </div>

      )
    }
}

export connector()(Users)
export const useReduxState = ({ id, defaultValues }) => {
  const selectors = useReduxListCommonSelectors({
    keyword:'users'
  });

  return {
    ...selectors,

  };
};
这是一个简化的版本,说明了每件事的实际运作方式,但这是它的关键所在。同样,上面的所有代码都被抽象为一个状态文件,如
state users.js

然后,在我的类组件中,我只需要从
state users.js
导入
连接器
,如下所示:

const messages = [
  { action: 'GET', creator: 'get', connect: true },
  { action: 'POST', creator: 'post', connect: true },
  { action: 'CLEAR', creator: 'clear', connect: true },
];
const { connector } = stateGenerators({
   keyword: 'users', //redux node keyword
   messages: messages,
   selectorKeys: selectorKeys

}) 
import { connector } from 'state-users';

class Users extends Component {
    componentDidMount() {
       this.props.get();
    }
    componentWillUnmount() {
      this.props.clear();
    }
    render () {
      const { data } = this.props;
      return (
        <div>
        {data.map()}
        </div>

      )
    }
}

export connector()(Users)
export const useReduxState = ({ id, defaultValues }) => {
  const selectors = useReduxListCommonSelectors({
    keyword:'users'
  });

  return {
    ...selectors,

  };
};
该代码导致此错误:
React钩子“useSelector”不能在回调内部调用。

实际上,这意味着我不能只是传入一组我想要的选择键,然后让它吐回我的选择键

  • 第二,不能在条件句中放置钩子。因此,由于第一个想法失败,我在工厂函数中尝试了一种不同的方法,如下所示:
这将导致此错误:
React钩子“useSelector”被有条件地调用。在每个组件渲染中,必须以完全相同的顺序调用React挂钩

所以这也是一个令人沮丧的问题。但我认为我剩下的是,对于我的100个Redux节点中的每一个,我都必须编写一个定制的、详细的钩子,或多或少地复制
connect

我知道,我知道,钩子应该鼓励我以不同的方式思考,但我仍然需要从服务器获取数据并将其提供给组件,我需要遵循相同的基本模式100次。即使钩子使我的组件更加优雅(正如我所期望的那样),但想到手工编写100个左右的钩子,每个钩子都有相当数量的重复数据,而不是使用某种工厂方法自动创建它们,我还是会感到不安

帮忙


谢谢

不确定这是否对其他人有用,但我找到了一种适合我的方法。我不能在迭代器中设置钩子,也不能在
if
语句中设置钩子,但我确实有很多通用的模式。因此,答案是将这些常见模式抽象为泛型钩子。例如,我有一个名为
useCommonReduxListSelectors
的钩子,它如下所示:

export const useReduxListCommonSelectors = (keyword: string) => {
  return {
    data: useSelector((state: any) => state[keyword].data),
    errorMessage: useSelector((state: any) => state[keyword].errorMessage),
    filters: useSelector((state: any) => state[keyword].filters),
    pending: useSelector((state: any) => state[keyword].pending),
    totalCount: useSelector((state: any) => state[keyword].totalCount)
  };
};
我有很多Redux状态节点,它们负责处理从API返回的列表,大多数列表端点的数据形状如上图所示。因此,组件将调用的钩子使用
useReduxListCommonSelectors
,如下所示:

const messages = [
  { action: 'GET', creator: 'get', connect: true },
  { action: 'POST', creator: 'post', connect: true },
  { action: 'CLEAR', creator: 'clear', connect: true },
];
const { connector } = stateGenerators({
   keyword: 'users', //redux node keyword
   messages: messages,
   selectorKeys: selectorKeys

}) 
import { connector } from 'state-users';

class Users extends Component {
    componentDidMount() {
       this.props.get();
    }
    componentWillUnmount() {
      this.props.clear();
    }
    render () {
      const { data } = this.props;
      return (
        <div>
        {data.map()}
        </div>

      )
    }
}

export connector()(Users)
export const useReduxState = ({ id, defaultValues }) => {
  const selectors = useReduxListCommonSelectors({
    keyword:'users'
  });

  return {
    ...selectors,

  };
};

显然,
useReduxState
可以包含该节点所需的任何其他数据(actionCreators、自定义选择器等)。因此,它允许我将最常见的模式抽象到可重用的挂钩中,还可以根据需要灵活地向每个
useReduxState
实例添加自定义代码。

您能在
connector()(Users)
之后显示所需的行为吗,您不是在描述连接功能吗?您不能在功能组件中使用连接的内容。我希望能够通过功能组件中的挂钩连接到redux……是的,我想我正在描述connect的挂钩版本。但更具体地说,我正在尽可能避免使用钩子样板。我想我了解如何编写connect的钩子版本,但我不想最后重复同样的详细钩子代码100x,因此希望有某种工厂解决方案。在搜索“react hook factory”时发现了这个问题,并惊讶于我们正在做完全相同的事情:)@AndrewCraswell FWIW,我现在有点讨厌钩子工厂模式,至少对我自己来说是这样,因为我发现它太抽象了,我总是不得不研究钩子工厂函数来看看它到底做了什么。它为我节省了一些代码行,但增加了我的整体混乱。一如既往,YMMV。(-;