Как смешать useCallback с useRef в функциональных компонентах - PullRequest
0 голосов
/ 14 марта 2020

Я новичок sh Реагирую и работаю над бесконечным компонентом прокрутки. Несколько компонентов будут использовать бесконечную прокрутку и должны быть синхронизированы вместе (т.е. прокрутка одного элемента программно прокручивает и другие компоненты).

Итак, я создал ScrollProvider, который поддерживает состояние прокрутки между компонентами (даже если они перерисованы), а ловушка более низкого уровня useScrollSync. useScrollState возвращает ссылку и обратный вызов handleScroll, который изменяет состояние в провайдер прокрутки. Это все работает просто отлично. Тем не менее, я отдельно хочу измерить размер компонента. В примере, представленном командой React, показан обратный вызов, поскольку он наверняка будет выполнен после монтирования компонента, и элемент не будет иметь значение null. Проблема в том, что у div уже есть ссылка из ловушки useScrollSyn c.

Основной вопрос

Если бы я хотел измерить мой div в дополнение к использованию scroll syn c на нем, как я могу назначить оба обратных вызова? ref И другие ссылки на это? Есть ли шаблон вокруг этого, учитывая, что элемент может иметь только один div?

Некоторый (упрощенный) код:

ScrollProvider

const ScrollContext = React.createCreateContext();

const ScrollProvider = ({initialScrollTop, initialScrollLeft}) => {
  const controlledElements = useRef(new Map());
  const scrollPositions = useRef({
    scrollTop: initialScrollTop, 
    scrollLeft: initialScrollLeft, 
    controllingElementKey: null
  });

  const register = (key, controlledElementRef) => {
    controlledElements.current.set(key, controlledElementRef);
  }

  const handleScrollHOF = (key) => { 
    return () => { 
      scrollPositions.controllingElementKey = key;
      //some scrolling logic
    }
  }

  return {register, scrollPositions, handleScrollHOF};

}

useScrollSyn c

const useScrollSync = () => { 
  const scrollContext = useContext(ScrollContext);

  const elementRef = useRef(null);
  const keyRef = useRef({key: Symbol()}); // this probably could also be useState

  useEffect(() => {
    scrollContext.register(keyRef, elementRef);
  }, []);

return {ref: elementRef, handleScroll: handleScrollHOF(keyRef.current)};
}

SomeComponent (Round 1)

const SomeComponent = () => {
  // this would be within the provider tree
  const {ref, handleScroll} = useScrollSync();

  return (
    <div onScroll={handleScroll} ref={ref}>some stuff</div>
  )
}

Теперь задача заключается в добавлении в крюк измерений ...

useMeasurements

const useMeasurements = () => {
  // something like this, per the React team's Hooks FAQ
  const [measurements, setMeasurements] = useState(null);

  const measurementRef = useCallback((element) => {
    if(element !== null) {
      setMeasurements(element.getBoundingClientRect());
    }
  });

  return {measurementRef, measurements};
}

Чтобы добавить это к SomeComponent ... SomeComponent (Round 2)

const SomeComponent = () => {
  // this would be within the provider tree
  const {ref, handleScroll} = useScrollSync();
  const {measurementRef, measurements} = useMeasurements();
  // I cannot assign measurementRef to this same div, 
  // and changing useMeasurements to just measure an injected ref winds up
  // with that ref being null and it never being recalculated

  return (
    <div onScroll={handleScroll} ref={ref}>some stuff</div>
  )
}

Я тут как-то врезался в стену, или, может быть, я просто переутомился. Есть мысли о том, как выйти за пределы этого?

1 Ответ

0 голосов
/ 14 марта 2020

Основная проблема, которую я вижу, заключается в том, что вы не ссылаетесь на реальную ссылку в useMeasurement. Кроме того, useCallback выполняется синхронно как часть рендеринга перед созданием DOM. Вам нужно будет сослаться на ваш элемент в другом хуке useEffect.

...