React Hooks Прокрутите до элемента

Я хочу написать хук React с React 16.8.6, который позволит мне прокручивать до определенного раздела элемента HTML при щелчке элемента навигации. У меня есть компонент Navigation, который является братом разделов, отображаемых на странице.

Также, когда страница прокручивается, я хотел бы обновить состояние App с помощью этого раздела HTML.

Компонент навигации 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.info(sectionRef.current);
    if (sectionRef.current) {
      sectionRef.current.scrollToItem();
    }
}, []);

Ваша навигация и разделы хранятся в одном файле компонента?

Chris Ngo 03.06.2019 05:04

Обновленное описание... Компонент <Nav/> отделен от этих разделов, но они отображаются на этой единственной странице.

Mark A 03.06.2019 05:30
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
11
2
18 866
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы не возражаете против использования react-router-dom, вы можете отслеживать изменения истории и обновлять положение прокрутки до id элемента HTML с помощью hash изменения истории. Преимущество этого подхода в том, что вам не нужно использовать ни состояние, ни ссылки, и он может масштабироваться по всему приложению (независимо от того, где расположены элементы в дереве приложения, вы можете прокручивать их).

Рабочий пример:

https://fglet.codesandbox.io/ (демо)

https://codesandbox.io/s/fglet (источник -- к сожалению, не работает в редакторе codeandbox)


компоненты/ScrollHandler (хук, который прослушивает изменения истории хеша, ищет элементы, которые соответствуют идентификатору, расположенному в хэше, и, если он находит соответствующий идентификатор элемента, то он прокручивается до элемента)

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"));

Другие вопросы по теме