programing

참조가 DOM 요소를 가리킬 때 useEffect의 종속성으로 ref.current를 사용하는 것이 안전합니까?

goodsources 2023. 3. 12. 10:45
반응형

참조가 DOM 요소를 가리킬 때 useEffect의 종속성으로 ref.current를 사용하는 것이 안전합니까?

ref는 가변 컨테이너이므로 다음 목록에 기재되어서는 안 됩니다.useEffect단, 의 의존관계ref.current값이 바뀔 수 있습니다.

참조를 사용하여 다음과 같은 DOM 요소를 저장하는 경우<div ref={ref}>그 요소에 의존하는 커스텀 훅을 개발하면 다음과 같이 됩니다.ref.current는 컴포넌트가 조건부로 반환되는 경우 다음과 같이 시간이 지남에 따라 변경될 수 있습니다.

const Foo = ({inline}) => {
  const ref = useRef(null);
  return inline ? <span ref={ref} /> : <div ref={ref} />;
};

커스텀 이펙트를 수신해도 안전한가?ref목적과 용도ref.current의존관계로요?

const useFoo = ref => {
  useEffect(
    () => {
      const element = ref.current;
      // Maybe observe the resize of element
    },
    [ref.current]
  );
};

코멘트를 읽은 적이 있는데, 레퍼런스는 다음 코멘트를useEffect하지만 어떤 경우든 알 수 없는 경우라도ref.current변경되지만 효과는 트리거되지 않습니다.

이 문제가 시사하는 바와 같이 콜백 ref를 사용해야 하는데, ref as 인수는 여러 후크를 통합하는 데 매우 편리합니다.

const ref = useRef(null);
useFoo(ref);
useBar(ref);

사용자가 콜백 참조를 작성하도록 강제되기 때문에 콜백 참조를 사용하는 것은 어렵습니다.

const fooRef = useFoo();
const barRef = useBar();
const ref = element => {
  fooRef(element);
  barRef(element);
};

<div ref={ref} />

이래서 사용해도 안전한지 물어보는 거야ref.currentuseEffect.

참조를 변환해도 렌더가 트리거되지 않기 때문에 안전하지 않습니다. 따라서작업은useEffect.

React Hook useEffect에는 'ref.current'라는 불필요한 종속성이 있습니다.제외하거나 종속 어레이를 제거합니다.'ref.current'와 같은 변환 가능한 값은 변환해도 구성 요소가 다시 렌더링되지 않으므로 유효한 종속성이 아닙니다.(예비/예비/예비/예비)

안티 패턴의 예를 다음에 나타냅니다.

const Foo = () => {
  const [, render] = useReducer(p => !p, false);
  const ref = useRef(0);

  const onClickRender = () => {
    ref.current += 1;
    render();
  };

  const onClickNoRender = () => {
    ref.current += 1;
  };

  useEffect(() => {
    console.log('ref changed');
  }, [ref.current]);

  return (
    <>
      <button onClick={onClickRender}>Render</button>
      <button onClick={onClickNoRender}>No Render</button>
    </>
  );
};

xenodocial-snowflake-hhgr6 편집


패턴과 관련된 실제 사용 사례요소가 마운트 해제된 경우에도 지속적인 참조를 원하는 경우입니다.

다음 예에서는 마운트 해제 시 요소의 크기를 유지할 수 없습니다.사용해보도록 하겠습니다.useRef와 함께useEffect콤보이지만 동작하지 않습니다.

// BAD EXAMPLE, SEE SOLUTION BELOW
const Component = () => {
  const ref = useRef();

  const [isMounted, toggle] = useReducer((p) => !p, true);
  const [elementRect, setElementRect] = useState();

  useEffect(() => {
    console.log(ref.current);
    setElementRect(ref.current?.getBoundingClientRect());
  }, [ref.current]);

  return (
    <>
      {isMounted && <div ref={ref}>Example</div>}
      <button onClick={toggle}>Toggle</button>
      <pre>{JSON.stringify(elementRect, null, 2)}</pre>
    </>
  );
};

잘못된 예 편집, 참조는 마운트 해제를 처리하지 않습니다.


놀랍게도 이걸 고치려면node직접 기능을 메모하면서useCallback:

// GOOD EXAMPLE
const Component = () => {
  const [isMounted, toggle] = useReducer((p) => !p, true);
  const [elementRect, setElementRect] = useState();

  const handleRect = useCallback((node) => {
    setElementRect(node?.getBoundingClientRect());
  }, []);

  return (
    <>
      {isMounted && <div ref={handleRect}>Example</div>}
      <button onClick={toggle}>Toggle</button>
      <pre>{JSON.stringify(elementRect, null, 2)}</pre>
    </>
  );
};

편집 모범 사례, 노드를 직접 처리합니다.

2021년 답변:

이 문서에서는 참조를 사용하는 경우의 문제에 대해 설명합니다.useEffect: useEffect Hook 내부의 오브젝트를 참조합니다.

렌더링을 건너뛰는 useEffect와 결합하면 useRef 훅은 사용자 지정 후크의 트랩이 될 수 있습니다.첫 번째 본능은 useEffect의 두 번째 인수에 ref.current를 추가하는 것입니다.그러면 ref가 변경되면 갱신됩니다.단, 참조는 컴포넌트가 렌더링될 때까지 갱신되지 않습니다.즉, 렌더링을 건너뛰는 useEffect는 다음 렌더 패스 전에 참조에 대한 변경을 볼 수 없습니다.

또한 이 문서에서 설명한 바와 같이 공식 반응 문서는 권장 접근법(Ref + Effect 대신 콜백을 사용)으로 업데이트되었습니다.DOM 노드를 측정하는 방법을 참조하십시오.

function MeasureExample() {
  const [height, setHeight] = useState(0);

  const measuredRef = useCallback(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  }, []);

  return (
    <>
      <h1 ref={measuredRef}>Hello, world</h1>
      <h2>The above header is {Math.round(height)}px tall</h2>
    </>
  );
}

같은 문제에 직면하여 Typescript를 사용한 커스텀 훅과 ref 콜백을 사용한 공식 접근 방식을 작성했습니다.그것이 도움이 되기를 바랍니다.

export const useRefHeightMeasure = <T extends HTMLElement>() => {
  const [height, setHeight] = useState(0)

  const refCallback = useCallback((node: T) => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height)
    }
  }, [])

  return { height, refCallback }
}

는 ESLint가 는는ained complainedainedainedainedainedainedainedainedained i i 、 ained 、 ained 、 、 。 에슬린트ref.current의 사용방법useCallback이 경고를 피하기 위해 프로젝트에 커스텀 훅을 추가했습니다.하여 변수 을 강제합니다.useCallback참조 객체가 변경될 때마다.

import { RefObject, useCallback, useRef, useState } from "react";

/**
 * This hook can be used when using ref inside useCallbacks
 * 
 * Usage
 * ```ts
 * const [toggle, refCallback, myRef] = useRefWithCallback<HTMLSpanElement>();
 * const onClick = useCallback(() => {
    if (myRef.current) {
      myRef.current.scrollIntoView({ behavior: "smooth" });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [toggle]);
  return (<span ref={refCallback} />);
  ```
 * @returns 
 */
function useRefWithCallback<T extends HTMLSpanElement | HTMLDivElement | HTMLParagraphElement>(): [
  boolean,
  (node: any) => void,
  RefObject<T>
] {
  const ref = useRef<T | null>(null);
  const [toggle, setToggle] = useState(false);
  const refCallback = useCallback(node => {
    ref.current = node;
    setToggle(val => !val);
  }, []);

  return [toggle, refCallback, ref];
}

export default useRefWithCallback;

되었습니다.useRef '만들면 돼요'라고 써주세요useState2회:1회 2회:

const [myChart, setMyChart] = useState(null)

const [el, setEl] = useState(null)
useEffect(() => {
    if (!el) {
        return
    }
    // attach to element
    const myChart = echarts.init(el)
    setMyChart(myChart)
    return () => {
        myChart.dispose()
        setMyChart(null)
    }
}, [el])

useEffect(() => {
    if (!myChart) {
        return
    }
    // do things with attached object
    myChart.setOption(... data ...)
}, [myChart, data])

return <div key='chart' ref={setEl} style={{ width: '100%', height: 1024 }} />

차트 작성, 인증 및 기타 비반응 라이브러리에 유용합니다. 요소 참조 및 초기화된 개체를 주변에 유지하고 필요에 따라 직접 폐기할 수 있기 때문입니다.

그런지useRef초에에 존재 ?? ???

언급URL : https://stackoverflow.com/questions/60476155/is-it-safe-to-use-ref-current-as-useeffects-dependency-when-ref-points-to-a-dom

반응형