React Hook, который ссылается на элемент DOM, возвращает «ноль» при первом вызове - PullRequest
0 голосов
/ 05 октября 2019

У меня есть ловушка, которая ловит getBoundingClientRect объект элемента ref DOM. Проблема в том, что при первом рендеринге он возвращает null, и мне нужно получить значение только при первом рендеринге для моего компонента.

Я использую его в функциональном компоненте так:

const App = () => {

  // create ref 
  const rootRef = useRef(null);

  // get Client Rect of rootRef 
  const refRect = useBoundingClientRect(rootRef);

  useEffect(()=> {
    // return "null" the first time
    // return "DOMRect" when refRect is update
    console.log(refRect)
  }, [refRect])

  return <div ref={rootRef} >App</div>

}

Здесь перехватчик useBoundingClientRect, который я вызываю в компоненте приложения.

export function useBoundingClientRect(pRef) {

  const getBoundingClientRect = useCallback(() => {
    return pRef && pRef.current && pRef.current.getBoundingClientRect();
  }, [pRef]);

  const [rect, setRect] = useState(null);

  useEffect(() => {
    setRect(getBoundingClientRect());
  },[]);

  return rect;
}

Проблема заключается в том, что я хотел бы кэшировать объект boundingClientRect при инициализации, а не во второй раз, когда компонент перерисовывается:

  // App Component

  useEffect(()=> {
    // I would like to get boundingClientRect the 1st time useEffect is call.
    console.log(refRect)

  // empty array allow to not re-execute the code in this useEffect
  }, [])

Я проверил несколько учебников и документов и обнаружил, что некоторые люди используют useRef вместо useState ловушки, чтобы сохранить ценность. Поэтому я попытался использовать его в своем хуке useboundingClientRect, чтобы перехватить и вернуть значение boundingClientRect при первом рендеринге моего компонента приложения. И это работает ... частично:

export function useBoundingClientRect(pRef) {

  const getBoundingClientRect = useCallback(() => {
    return pRef && pRef.current && pRef.current.getBoundingClientRect();
  }, [pRef]);

  const [rect, setRect] = useState(null);

  // create a new ref
  const rectRef = useRef(null)

  useEffect(() => {
    setRect(getBoundingClientRect());

    // set value in ref
    const rectRef = getBoundingClientRect()

  },[]);

  //  return rectRef for the first time 
  return rect === null ? rectRef : rect;
}

Теперь console.log(rectRef) в компоненте приложения позволяет получить доступ к значению при первом рендеринге:

   // App Component

  useEffect(()=> {
    console.log(refRect.current)
  }, [])

Но если я пытаюсь вернуться refRect.current от useBoundingClientRect возврат крюка null. (Что?!)

, если кто-нибудь сможет объяснить мне эти ошибки. Заранее спасибо!

1 Ответ

1 голос
/ 05 октября 2019

Вы должны понимать ссылки, мутации и асинхронный характер обновления здесь

Во-первых, когда вы используете состояние для хранения свойств clientRect, когда вы выполняете пользовательские перехваты useEffect, он устанавливает значение в состояниикоторый будет отражаться в следующем цикле рендеринга, поскольку обновление состояния является асинхронным, поэтому при первом рендеринге вы видите неопределенное.

Во-вторых, когда вы возвращаете rectRef, вы, по сути, возвращаете объект, который вы впоследствии мутируетекогда useEffect in useBoundingClientRect работает. Данные возвращаются до запуска useEffect, так как он выполняется после цикла рендеринга. Теперь, когда useEffect в компоненте (то есть после useEffect в настраиваемом хуке) выполняется, данные уже там и были обновлены по его ссылке предыдущим useEffect, и, следовательно, вы видите правильные данные.

Однако здесь, если вы возвращаете rectRef.current, которое теперь является неизменяемым значением, пользовательский хук обновляет значение, но с новой ссылкой, поскольку предыдущая была null, и, следовательно, вы не видите изменений в ваших компонентах useEFfectспособ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...