首页 > 解决方案 > 将流/类组件重写为自定义钩子

问题描述

我正在尝试在此处重写以下代码,该代码是按流程编写的,以自定义挂钩。我被卡住了,钩子不能正常工作。你看到我犯了什么错误吗?

我得到的错误是TypeError: elementRefs.ref is not a function

我是这样称呼它的:

父.js

import MultiRef from "./MultiRef";

const [elementRefs] = useState(() => new MultiRef());

这是我的版本:

function useMultiRef() {
  const map = new Map();
  const _refFns = new Map();

  const ref = (key) => {
    let refFn = _refFns.get(key);
    if (!refFn) {
      refFn = (value) => {
        if (value == null) {
          _refFns.delete(key);
          map.delete(key);
        } else {
          map.set(key, value);
        }
      };
      _refFns.set(key, refFn);
    }
    return refFn;
  };
}

export default useMultiRef;

这是原始代码:

/* @flow */

type RefFn<V> = (value: V|null) => mixed;

export default class MultiRef<K,V> {
  map: Map<K,V> = new Map();

  _refFns: Map<K,RefFn<V>> = new Map();

  ref(key: K): RefFn<V> {
    let refFn: ?RefFn<V> = this._refFns.get(key);
    if (!refFn) {
      refFn = value => {
        if (value == null) {
          this._refFns.delete(key);
          this.map.delete(key);
        } else {
          this.map.set(key, value);
        }
      };
      this._refFns.set(key, refFn);
    }
    return refFn;
  }
}

更新(parent.js):

/**
 * Scrolls to element if var goToElement is set
 */
useEffect(() => {
  const ref = elementRefs.map.get(goToElement);
  // If no ref exists, scroll to top of the floor instead
  if (!ref) {
    floorRef.current.scrollTop = 0;
    return;
  }
  // Scroll to element: scrollTo(x-coord, y-coord)
  floorRef.current.scrollTo(0, ref.offsetTop);
  // Wait for a short time to perform scrolling
  const timer = setTimeout(() => {
    // currentElementRef is needed for highlighting the element
    setCurrentElementRef(ref);
  }, 500);

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

标签: javascriptreactjs

解决方案


您需要返回refelementRefs.ref才能工作,目前,您只需运行一个 void 函数。

此外,这不是您实现简单功能的自定义钩子。

function multiRef() {
  //...
  const ref = (key) => {...};

  return { ref };
}

自定义钩子应该使用 hooks来获得类似于类的属性,它应该看起来像:

function useMultiRef() {
  const map = useRef(new Map());
  const _refFns = useRef(new Map());

  const ref = useCallback((key) => {
    let refFn = _refFns.current.get(key);
    if (!refFn) {
      refFn = (value) => {
        if (value == null) {
          _refFns.current.delete(key);
          map.current.delete(key);
        } else {
          map.current.set(key, value);
        }
      };
      _refFns.current.set(key, refFn);
    }
    return refFn.current;
  }, []);

  return { ref, map };
}

export default useMultiRef;

推荐阅读