首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >修复函数组件主体外的钩子调用

修复函数组件主体外的钩子调用
EN

Stack Overflow用户
提问于 2022-02-07 23:28:42
回答 1查看 139关注 0票数 0

我做了一个定制的ReactJS钩子来处理几个特定的鼠标事件,如下所示:

代码语言:javascript
复制
const HealthcareServices = ({
  filterToRemove,
  filters,
  onChange,
  onClear,
  selectedAmbulatoryCareFilterValue,
  shouldClear,
}: Props): JSX.Element => {
  const classes = useStyles();
  ...

  useEffect(() => {
    shouldClear && clearFilters();
  }, [shouldClear]);

  const useSingleAndDoubleClick = (actionSimpleClick: () => void, actionDoubleClick: () => void, delay = 250) => {
    const [click, setClick] = useState(0);

    useEffect(() => {
      const timer = setTimeout(() => {
        // simple click
        if (click === 1) actionSimpleClick();
        setClick(0);
      }, delay);

      // the duration between this click and the previous one
      // is less than the value of delay = double-click
      if (click === 2) actionDoubleClick();

      return () => clearTimeout(timer);
    }, [click]);

    return () => setClick((prev) => prev + 1);
  };

  const handleSelectedItem = (service: Filter) => {
    service.selected = !service.selected;
    setHealthcareServices([...healthcareServices]);
    onChange(healthcareServices);
  };

  const handleSingleClick = (service: Filter) => {
    console.log('single-click');
    if (service.isRequired) {
      service.checkedIcon = <Icons.CheckboxSingleClick />;
    }
    handleSelectedItem(service);
  };

  const handleDoubleClick = (service: Filter) => {
    console.log('double-click');
    if (service.isRequired) {
      service.checkedIcon = <Icons.CheckboxDoubleClick />;
    }
    handleSelectedItem(service);
  };

  const handleClick = (service: Filter) =>
    useSingleAndDoubleClick(
      () => handleSingleClick(service),
      () => handleDoubleClick(service)
    );
  ...

  return (
    <div className={classes.filter_container}>
      ...
      <div className={classes.filter_subgroup}>
        {filters.map((filter) => (
          <div key={`${filter.label}-${filter.value}`} className={classes.filter}>
            <Checkbox
              label={filter.label}
              className={classes.checkbox}
              checked={filter.selected}
              onChange={() => handleClick(filter)}
              checkedIcon={filter.checkedIcon}
            />
          </div>
        ))}
      </div>
      ...
    </div>
  );
};

当我点击我的<Checkbox />时,整个系统就崩溃了。错误是:

我的堆栈跟踪的顶部指向我的钩子中的useState。如果我把它移到外面,这个钩子看起来是:

代码语言:javascript
复制
const [click, setClick] = useState(0);

const useSingleAndDoubleClick = (actionSimpleClick: () => void, actionDoubleClick: () => void, delay = 250) => {

    useEffect(() => {
      const timer = setTimeout(() => {
        // simple click
        if (click === 1) actionSimpleClick();
        setClick(0);
      }, delay);

      // the duration between this click and the previous one
      // is less than the value of delay = double-click
      if (click === 2) actionDoubleClick();

      return () => clearTimeout(timer);
    }, [click]);

    return () => setClick((prev) => prev + 1);
  };

问题仍然发生,只有堆栈跟踪指向useEffect钩子。代码基于另一个答案here

有什么建议吗?

EN

回答 1

Stack Overflow用户

发布于 2022-02-08 04:22:59

您已经在组件中定义了useSingleAndDoubleClick钩子。这不是你想做的。自定义钩子的思想是,您可以将逻辑移出组件之外,否则只能在组件内部发生。这有助于代码重用。

在函数中定义钩子是没有用的,因为钩子的神奇之处在于它们允许您访问状态变量以及通常只允许与内部函数组件交互的事情。

您需要在组件外部定义钩子并在组件中调用它,或者删除useSingleAndDoubleClick的定义,只需在组件中完成所有操作。

编辑:还有一个注意事项可以帮助澄清:这里您真正打破的规则是,您在您的useState函数中调用了其他挂钩(即,useSingleAndDoubleClick、useEffect)。尽管它被称为useSingleAndDoubleClick,但它实际上并不是一个钩子,因为它没有被创建或调用为一个钩子。因此,您不允许在其中调用其他钩子。

编辑:我在前面提到过这一点,但是下面是一个可以将钩子定义移出函数的示例:

编辑:还必须更改调用钩子的位置:不能在嵌套函数中调用钩子,但我不认为需要调用钩子。

代码语言:javascript
复制
const useSingleAndDoubleClick = (actionSimpleClick: () => void, actionDoubleClick: () => void, delay = 250) => {
    const [click, setClick] = useState(0);

    useEffect(() => {
      const timer = setTimeout(() => {
        // simple click
        if (click === 1) actionSimpleClick();
        setClick(0);
      }, delay);

      // the duration between this click and the previous one
      // is less than the value of delay = double-click
      if (click === 2) actionDoubleClick();

      return () => clearTimeout(timer);
    }, [click]);

    return () => setClick((prev) => prev + 1);
  };

const HealthcareServices = ({
  filterToRemove,
  filters,
  onChange,
  onClear,
  selectedAmbulatoryCareFilterValue,
  shouldClear,
}: Props): JSX.Element => {
  const classes = useStyles();
  ...

  useEffect(() => {
    shouldClear && clearFilters();
  }, [shouldClear]);
  // your other handlers

  // changed this - don't call the hook inside the function.
  // your hook is returning the handler you want anyways, I think
  const handleClick = useSingleAndDoubleClick(handleSingleClick, handleDoubleClick)
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71026732

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档