반응에서보기로 스크롤

Nov 23 2020

두 가지가있는 간단한 반응 앱을 만들고 있습니다 div's.

선택 입력 및 선택 목록이있는 하나,

  <div id="container">
    <div className="_2iA8p44d0WZ">
      <span className="chip _7ahQImy">Item One</span>
      <span className="chip _7ahQImy">Item Two</span>
      <span className="chip _7ahQImy">Item Three</span>
      <span className="chip _7ahQImy">Item Four</span>
      <span className="chip _7ahQImy">Item Five</span>
      <input
        type="text"
        className="searchBox"
        id="search_input"
        placeholder="Select"
        autoComplete="off"
        value=""
      />
    </div>
  </div>

다른 옵션은 선택한 옵션을 fieldset,

  <div>
    {selectedElements.map((item, i) => (
      <div key={i} className="selected-element" ref={scrollDiv}>
        <fieldset>
          <legend>{item}</legend>
        </fieldset>
      </div>
    ))}
  </div>

이 솔루션을 기반으로 createRef선택한 요소에 다음과 같이 추가 했습니다.

<div key={i} className="selected-element" ref={scrollDiv}>
</div>

그런 다음 Javascript 쿼리 메서드를 사용하여 다음과 같은 DOM 요소를 얻었습니다.

  const chipsArray = document.querySelectorAll("#container > div > .chip");

다음과 같은 모든 요소에 클릭 이벤트 리스너를 추가했습니다.

  chipsArray.forEach((elem, index) => {
    elem.addEventListener("click", scrollSmoothHandler);
  });

그런 다음 scrollSmoothHandler, 같은

const scrollDiv = createRef();

  const scrollSmoothHandler = () => {
    console.log(scrollDiv.current);
    if (scrollDiv.current) {
      scrollDiv.current.scrollIntoView({ behavior: "smooth" });
    }
  };

그러나 이것은 예상대로 작동하지 않습니다.

요구 사항 :

의 항목을 클릭 first div하면 관련 fieldset이 smooth scrolled다른 div에 있어야합니다 .

예 : 사용자가 Item Four아래 의 요소를 클릭하면<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>

그런 다음 관련 필드 세트를 스크롤해야합니다. 여기에 범례가 Item Four..

나는 또한 반응에 js dom 쿼리 메서드를 만드는 것으로 생각하며 반응 구현 방법이 아닌 것 같습니다. 누구든지 선택한 항목을 클릭하면 관련 필드 세트로 스크롤 한 결과를 얻을 수 있도록 친절하게 도와 주시겠습니까?.

답변

1 DrewReese Nov 24 2020 at 13:22

발행물

  1. React.createRef클래스 기반 구성 요소에서만 유효합니다. 기능적 구성 요소 본문에서 사용되는 경우 참조는 각 렌더링주기를 다시 생성합니다.
  2. DOM 쿼리 선택기를 사용하여 onClick리스너를 DOM 요소 에 연결하지 마십시오 . 이것들은 외부에서 반응하므로 메모리 누수가 발생하지 않도록 정리 (즉, 제거)하는 것을 기억해야합니다. React의 onClick소품을 사용하십시오 .
  3. selectedElements이 매핑 되면 각 요소에 동일한 참조를 첨부 하므로 마지막 세트가 UI가 가져 오는 것입니다.

해결책

  1. 사용 React.useRef당신이보기에 스크롤 할 각 요소에 첨부 심판 반응의 기능 컴포넌트 몸에 배열을 저장합니다.
  2. scrollSmoothHandler각각 spanonClick소품에 직접 부착하십시오 .
  3. 1에서 생성 된 참조 배열의 각 참조를 스크롤하려는 각 매핑 된 필드 세트에 연결합니다.

암호

import React, { createRef, useRef } from "react";
import { render } from "react-dom";

const App = () => {
  const selectedElements = [
    "Item One",
    "Item Two",
    "Item Three",
    "Item Four",
    "Item Five"
  ];

  // React ref to store array of refs
  const scrollRefs = useRef([]);

  // Populate scrollable refs, only create them once
  // if the selectedElements array length is expected to change there is a workaround
  scrollRefs.current = [...Array(selectedElements.length).keys()].map(
    (_, i) => scrollRefs.current[i] ?? createRef()
  );

  // Curried handler to take index and return click handler
  const scrollSmoothHandler = (index) => () => {
    scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
  };

  return (
    <div>
      <div id="container">
        <div className="_2iA8p44d0WZ">
          {selectedElements.map((el, i) => (
            <span
              className="chip _7ahQImy"
              onClick={scrollSmoothHandler(i)} // <-- pass index to curried handler
            >
              {el}
            </span>
          ))}
          <input
            type="text"
            className="searchBox"
            id="search_input"
            placeholder="Select"
            autoComplete="off"
            value=""
          />
        </div>
      </div>
      <div>
        {selectedElements.map((item, i) => (
          <div
            key={i}
            className="selected-element"
            ref={scrollRefs.current[i]} // <-- pass scroll ref @ index i
          >
            <fieldset>
              <legend>{item}</legend>
            </fieldset>
          </div>
        ))}
      </div>
    </div>
  );
};

솔루션 # 2

divwith의 어떤 요소도 업데이트 할 수없고 id="container"모든 onClick핸들러가 DOM 쿼리를 통해 연결되어야하므로 커리 scrollSmoothHandler콜백을 사용하고 범위에 인덱스를 포함 할 수 있습니다. 초기 렌더링 useEffect DOM을 쿼리 하는 후크가 필요 하므로 스팬이 마운트되고 "로드 됨"상태를 저장 하는 후크가 필요합니다. 상태는 다시 렌더링을 트리거 하고 콜백 에서 다시 묶는 데 필요합니다 .useStatescrollRefsscrollSmoothHandler

const App = () => {
  const selectedElements = [
    "Item One",
    "Item Two",
    "Item Three",
    "Item Four",
    "Item Five"
  ];

  const [loaded, setLoaded] = useState(false);
  const scrollRefs = useRef([]);

  const scrollSmoothHandler = (index) => () => {
    scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
  };

  useEffect(() => {
    const chipsArray = document.querySelectorAll("#container > div > .chip");

    if (!loaded) {
      scrollRefs.current = [...Array(chipsArray.length).keys()].map(
        (_, i) => scrollRefs.current[i] ?? createRef()
      );

      chipsArray.forEach((elem, index) => {
        elem.addEventListener("click", scrollSmoothHandler(index));
      });
      setLoaded(true);
    }
  }, [loaded]);

  return (
    <div>
      <div id="container">
        <div className="_2iA8p44d0WZ">
          <span className="chip _7ahQImy">Item One</span>
          <span className="chip _7ahQImy">Item Two</span>
          <span className="chip _7ahQImy">Item Three</span>
          <span className="chip _7ahQImy">Item Four</span>
          <span className="chip _7ahQImy">Item Five</span>
          <input
            type="text"
            className="searchBox"
            id="search_input"
            placeholder="Select"
            autoComplete="off"
            value=""
          />
        </div>
      </div>
      <div>
        {selectedElements.map((item, i) => (
          <div key={i} className="selected-element" ref={scrollRefs.current[i]}>
            <fieldset>
              <legend>{item}</legend>
            </fieldset>
          </div>
        ))}
      </div>
    </div>
  );
};