为了账号安全,请及时绑定邮箱和手机立即绑定

滚动到反应视图中

滚动到反应视图中

森栏 2023-08-24 10:02:47
我正在制作一个简单的反应应用程序,其中有两个不同的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" });    }  };但这并没有按预期工作。
查看完整描述

1 回答

?
弑天下

TA贡献1818条经验 获得超7个赞

问题

  1. React.createRef实际上只在基于类的组件中有效。如果在功能组件主体中使用,则将在每个渲染周期重新创建引用。

  2. 不要使用 DOM 查询选择器将onClick侦听器附加到 DOM 元素。这些存在于外部反应,您需要记住清理它们(即删除它们),这样就不会出现内存泄漏。使用 React 的onClickprop。

  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>

  );

};


查看完整回答
反对 回复 2023-08-24
  • 1 回答
  • 0 关注
  • 107 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信