React Hooks 滚动到元素

Posted

技术标签:

【中文标题】React Hooks 滚动到元素【英文标题】:React Hooks Scroll to Element 【发布时间】:2019-10-18 14:20:07 【问题描述】:

我希望使用 React 16.8.6 编写一个 React 钩子,它可以让我在单击导航项时滚动到特定的 html 元素部分。我有一个 Navigation 组件,它是页面上呈现的部分的兄弟。

当页面滚动时,我想用那个 HTML 部分更新App 的状态。

导航组件 JSX

<ul class="nav>
   <li><a>Section 1</a></li>
   <li><a>Section 2</a></li>          
</ul>

应用级组件主页中的部分

<section className="section-1">Section 1</section>
<section className="section-2">Section 2</section>

挂钩


const [navItem, setNavItem] = React.useState(null);
const sectionRef = React.useRef(null);

// Scroll To Item
useEffect(() => 
    console.log(sectionRef.current);
    if (sectionRef.current) 
      sectionRef.current.scrollToItem();
    
, []);

【问题讨论】:

您的导航和部分是否保存在同一个组件文件中? 更新了描述... 组件与这些部分是分开的,但它们呈现在该单个页面上。 【参考方案1】:

如果您不介意使用react-router-dom,那么您可以跟踪历史更改并通过hash 历史更改将滚动位置更新为HTML 元素的id。这种方法的优点是您不必使用 state,也不必使用 refs,并且它可以在整个应用程序中扩展(无论元素位于应用程序树中的哪个位置,您都可以滚动到它们)。

工作示例

https://fglet.codesandbox.io/(演示)

https://codesandbox.io/s/fglet(来源——不幸的是,在代码框编辑器中不起作用)


components/ScrollHandler(监听哈希历史变化的钩子,搜索与哈希中的 id 匹配的元素,如果找到匹配的元素 id,它会滚动到元素)

import  useEffect  from "react";
import PropTypes from "prop-types";
import  withRouter  from "react-router-dom";

const ScrollHandler = ( location ) => 
  useEffect(() => 
    const element = document.getElementById(location.hash));

    setTimeout(() => 
      window.scrollTo(
        behavior: element ? "smooth" : "auto",
        top: element ? element.offsetTop : 0
      );
    , 100);
  , [location]);

  return null;
;

ScrollHandler.propTypes = 
  location: PropTypes.shape(
    pathname: PropTypes.string,
    search: PropTypes.string,
    hash: PropTypes.string,
    state: PropTypes.any,
    key: PropTypes.string
  ).isRequired
;

export default withRouter(ScrollHandler);

组件/导航(更改 url 哈希历史位置的链接)

import React from "react";
import  Link  from "react-router-dom";
import List from "../List";

const Navigation = () => (
  <List>
    [1, 2, 3, 4, 5].map(num => (
      <li key=num>
        <Link to=`/#section$num`>Section num</Link>
      </li>
    ))
  </List>
);

export default Navigation;

组件/部分Headline 组件包含将匹配的id

import React from "react";
import Headline from "../Headline";

const Sections = () =>
  [1, 2, 3, 4, 5].map(num => (
    <Headline key=num id=`#section$num`>
      Section num
    </Headline>
  ));

export default Sections;

index.js

import React from "react";
import  render  from "react-dom";
import  BrowserRouter  from "react-router-dom";

import Container from "./components/Container";
import Navigation from "./components/Navigation";
import Sections from "./components/Sections";
import ScrollHandler from "./components/ScrollHandler";
import "./styles.css";

const App = () => (
  <BrowserRouter>
    <Container>
      <ScrollHandler />
      <Navigation />
      <Sections />
    </Container>
  </BrowserRouter>
);

render(<App />, document.getElementById("root"));

【讨论】:

以上是关于React Hooks 滚动到元素的主要内容,如果未能解决你的问题,请参考以下文章

React Hooks setState 数组中的元素

使用 React Hooks 更改元素类名称和兄弟姐妹

使用 React Hooks 更新状态数组的所有对象元素

不受控制的输入 React Hooks

使用带有graphql的react hooks时,按钮元素中的onClick不会触发react-table中的重新渲染

React-DnD - 当顶部有固定元素时将元素拖动到屏幕顶部不会向上滚动页面