使用React Hooks在页面加载时滚动到元素

3
我正在尝试创建一个功能组件,从API获取数据并将其呈现到列表中。 在获取和呈现数据之后,我希望检查URL id和列表项是否相等,如果相等,则应将列表项滚动到视图中。
以下是我的代码:
import React, { Fragment, useState, useEffect, useRef } from "react";

export default function ListComponent(props) {
  const scrollTarget = useRef();

  const [items, setItems] = useState([]);
  const [scrollTargetItemId, setScrollTargetItemId] = useState("");

  useEffect(() => {
    const fetchData = async () => {
      let response = await fetch("someurl").then((res) => res.json());

      setItems(response);
    };
    
    fetchData();

    if (props.targetId) {
      setScrollTargetItemId(props.targetId)
    }

    if (scrollTarget.current) {
      window.scrollTo(0, scrollTarget.current.offsetTop)
    }
  }, [props]);

  let itemsToRender = [];
  itemsToRender = reports.map((report) => {   

    return (
      <li
        key={report._id}
        ref={item._id === scrollTargetItemId ? scrollTarget : null}
      >
        {item.payload}
      </li>
    );
  });

  return (
    <Fragment>
          <ul>{itemsToRender}</ul>
    </Fragment>
  );
}

我的问题是scrollTarget.current总是undefined。请指导我哪里做错了。提前感谢。


如果您使用useLayoutEffect而不是useEffect会怎样呢?它应该在所有内容都被渲染之后再运行。 - JulienD
4个回答

5

如@yagiro所建议,使用 useCallback 方法解决了问题!

我的代码最终变成了这样:

const scroll = useCallback(node => {
    if (node !== null) {
      window.scrollTo({
        top: node.getBoundingClientRect().top,
        behavior: "smooth"
      })
    }
  }, []);

然后,我只需要有条件地在想要滚动到的节点上设置ref={scroll}


也可以使用 node.scrollIntoView({behavior: 'smooth', block: 'start'}); - Shahin Dohan

1

这是因为当引用被改变时,它不会导致重新渲染。

来自 React 文档:https://reactjs.org/docs/hooks-reference.html#useref

请记住,useRef 在其内容更改时不会通知您。更改 .current 属性不会导致重新渲染。如果您想在 React 将 ref 附加到或分离出 DOM 节点时运行一些代码,则可能需要使用 回调 ref


0

React Hooks 会延迟滚动直到页面准备好:

useEffect(() => {
    const element = document.getElementById('id')
    if (element)
        element.scrollIntoView({ behavior: 'smooth' })
}, [])

如果元素是动态的且基于变量,请将它们添加到Effect hook中:
const [variable, setVariable] = useState()
const id = 'id'

useEffect(() => {
    const element = document.getElementById(id)
    if (element)
        element.scrollIntoView({ behavior: 'smooth' })
}, [variable])

0
      constructor(props) {
            thi.modal = React.createRef();
          
        }
    
    handleSwitch() {
            // debugger
            this.setState({ errors: [] }, function () {
                this.modal.current.openModal('signup') // it will call function of child component of Modal
            });
            // debugger
        }
    
    
    return(
    <>
 
    <button className="login-button" onClick={this.handleSwitch}>Log in with email</button>

  
    <Modal ref={this.modal} />

</>

    )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接