Прокрутіть до початку сторінки після візуалізації в react.js


168

У мене є проблема, яку я не маю ідеї, як вирішити. У своєму компоненті реагування я відображаю довгий список даних та кілька посилань внизу. Після натискання будь-якого з цих посилань я заповнюю список новою колекцією посилань і мені потрібно прокрутити до початку.

Проблема полягає в тому, - як прокрутити до початку після того, як нова колекція буде надана?

'use strict';

// url of this component is #/:checklistId/:sectionId

var React = require('react'),
  Router = require('react-router'),
  sectionStore = require('./../stores/checklist-section-store');


function updateStateFromProps() {
  var self = this;
  sectionStore.getChecklistSectionContent({
    checklistId: this.getParams().checklistId,
    sectionId: this.getParams().sectionId
  }).then(function (section) {
    self.setState({
      section,
      componentReady: true
    });
  });

    this.setState({componentReady: false});
 }

var Checklist = React.createClass({
  mixins: [Router.State],

  componentWillMount: function () {
    updateStateFromProps.call(this);
  },

  componentWillReceiveProps(){
    updateStateFromProps.call(this);
   },

render: function () {
  if (this.state.componentReady) {
    return(
      <section className='checklist-section'>
        <header className='section-header'>{ this.state.section.name }   </header>
        <Steps steps={ this.state.section.steps }/>
        <a href=`#/${this.getParams().checklistId}/${this.state.section.nextSection.Id}`>
          Next Section
        </a>
      </section>
    );
    } else {...}
  }
});

module.exports = Checklist;

Відповіді:


327

Нарешті .. я використав:

componentDidMount() {
  window.scrollTo(0, 0)
}

EDIT: React v16.8 +

useEffect(() => {
  window.scrollTo(0, 0)
}, [])

2
Це єдине рішення, яке працювало на мене. Також спробував: ReactDOM.findDOMNode (це) .scrollTop = 0 і компонентDidMount () {this._div.scrollTop = 0} render () {return <div ref = {(ref) => this._div = ref} />}
Майкл Буше

За даними W3Schools, це рішення на даний момент підтримується всіма браузерами. Також у майбутніх версіях React застаріла бібліотека ReactDOM.
BishopZ

2
@Tomasz - Я виявив, що у мене все ще виникають проблеми, коли у мене були певні диви, встановлені на висоту або мінімальну висоту: 100%. Мені довелося вийняти і або загорнути його в батьківське, або перенести далі в дерево, де воно ще може прокручуватися
рацемічне

2
Це працювало для мене, але не під компонент компонентDidMount, оскільки CDM може не запускатися, коли зміна стану призводить до повторного відображення сторінки. Тому поставте цей виклик - window.scrollTo (0, 0); - де б ви не змінили штат.
Puneet Lamba

4
Для тих, хто використовує гачки, спрацює наступний код. React.useEffect(() => { window.scrollTo(0, 0); }, []); Зверніть увагу, ви також можете імпортувати useEffect безпосередньо:import { useEffect } from 'react'
Powderham

72

Оскільки оригінальне рішення було надано для дуже ранньої версії реагування , ось оновлення:

constructor(props) {
    super(props)
    this.myRef = React.createRef()   // Create a ref object 
}

componentDidMount() {
  this.myRef.current.scrollTo(0, 0);
}

render() {
    return <div ref={this.myRef}></div> 
}   // attach the ref property to a dom element

this.getDOMNode === undefined
Дейв Ланні

1
@DaveLunny, можливо, ти можеш реагувати15? спробуйте імпортувати ReactDOM і робити ReactDOM.findDOMNode(this).scrollTop = 0
Marcus Ericsson

12
this is undefined in arrow functionsневірно. Це ключове слово пов'язане з тим же контекстом, що і функція, що додає developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Джо Дельгадо

Якщо можливо, слід уникати ReactDom.findDOMNode (). Використовуйте замість цього посилання. Тут я розмістив рішення, використовуючи гладку прокрутку
bbrinx

default.a.createRef не є функцією
Anupam Maurya

48

Ви могли б використовувати щось подібне. ReactDom призначений для реагування.14. Просто реагуйте інакше.

    componentDidUpdate = () => { ReactDom.findDOMNode(this).scrollIntoView(); }

Оновлення 5.11.2019 для React 16+

  constructor(props) {
    super(props)
    this.childDiv = React.createRef()
  }

  componentDidMount = () => this.handleScroll()

  componentDidUpdate = () => this.handleScroll()

  handleScroll = () => {
    const { index, selected } = this.props
    if (index === selected) {
      setTimeout(() => {
        this.childDiv.current.scrollIntoView({ behavior: 'smooth' })
      }, 500)
    }
  }


З усіх пропозицій на цій сторінці це єдине, що працює для мене.
Джош F

Примітка. Якщо компонентDidUpdate не працює для вас, componentDidMountце ще одна альтернатива.
Алекс Фалленштедт

findDOMNode - це люк для втечі, який використовується для доступу до базового вузла DOM. У більшості випадків використання цього люка для втечі не рекомендується, оскільки він пронизує абстрагування компонентів. У StrictMode це було застаріло. reactjs.org/docs/react-dom.html
Vivek Kumar

16

У React Routing є проблема, що якщо ми переспрямовуємо на новий маршрут, він автоматично не переведе вас у верхню частину сторінки.

Навіть у мене було те саме питання.

Я просто додав єдиний рядок до свого компонента, і він працював як масло.

componentDidMount() {
    window.scrollTo(0, 0);
}

Довідково: реагуйте на навчання


це рекомендований спосіб, якщо я використовую це для своєї кнопки "Перейти вгору"? або якщо є спосіб "реагувати", коли ми не використовуємо об'єкт вікна?
Toxnyc

1
Дякуємо за те, що ви звернули увагу, рішення, яке я запропонував, застосовується для версії dom reaktor-маршрутизатора менше, ніж v5, я використовував v4.2.2 і там, коли ви переходите на іншу сторінку, вас не брали за замовчуванням до вершини сторінки, тому після навігації ми повинні вручну підняти користувача до верхньої частини сторінки, але з v5.0.1 реакційним маршрутизатором dom припинено відновлення прокрутки з коробки, оскільки згідно з їх документом вони кажуть, що браузери почали підтримувати ця функція за замовчуванням та з останньою версією reakct-router-dom ви перейдете вгору сторінки після навігації.
Вішал Шетті

1
@Toxnyc, тому використання віконного об’єкта - це те, що є JavaScript, якщо реакція знаходиться на вершині Javascript, то навіть якщо ви використовуєте будь-який з плагінів React за лаштунками, він буде використовувати лише Javascript та об’єкт вікна, як на мою інформацію про реакцію знань немає. все, за допомогою чого ми можемо отримати деталі екрана вікна. нам потрібно працювати з Javascript, щоб він працював.
Вішал Шетті

13

З цим можна було б і, мабуть, вирішити за допомогою посилань :

"... ви можете використовувати ReactDOM.findDOMNode як" люк для втечі ", але ми не рекомендуємо його, оскільки він порушує інкапсуляцію, і майже в кожному випадку існує більш чіткий спосіб структурувати ваш код у моделі React."

Приклад коду:

class MyComponent extends React.Component {
    componentDidMount() {
        this._div.scrollTop = 0
    }

    render() {
        return <div ref={(ref) => this._div = ref} />
    }
}

Це чудово працює. Дякую. Щоб було зрозуміло, я ставлю це <div ref={(ref) => this._div = ref} />в першій <div>своїй заяві про надання. Решта моєї візуалізації залишається точно такою ж.
Джош Ф

Якщо ви використовуєте стильовані компоненти, вам потрібно буде використовувати "innerRef" замість "ref". Чудове рішення
furcicm

Всього працює. Що над тим, над чим я працював, я міг би бути ще простішим, <div ref="main">а потімthis.refs.main.scrollTop=0
чакфактор

2
@chuckfactory налаштування refs за допомогою рядків, ймовірно, буде видалено в якийсь момент, і насправді є деякі цікаві недоліки, про які ви можете дізнатися. news.ycombinator.com/edit?id=12093234
NJensen

10

Ви можете зробити це в маршрутизаторі так:

ReactDOM.render((
<Router onUpdate={() => window.scrollTo(0, 0)} history={browserHistory}>
     <Route path='/' component={App}>
        <IndexRoute component={Home}></IndexRoute>
        <Route path="/about" component={About}/>
        <Route path="/work">
            <IndexRoute component={Work}></IndexRoute>
            <Route path=":id" component={ProjectFull}></Route>
        </Route>
        <Route path="/blog" component={Blog}/>
    </Route>
 </Router>
), document.getElementById('root'));

onUpdate={() => window.scrollTo(0, 0)}Покласти зверху прокрутки. Для отримання додаткової інформації перевірте: посилання codepen


елегантне рішення, яке вимагає лише невеликої зміни коду в роутері, а не кожного компонента обробляти сам. <3
аленгель

На жаль, оновлення пожеж із кожним новим маршрутомParam, що проходить за певним маршрутом. Отже, якщо у вас, наприклад, є сторінка з купою зображень, і якщо ви можете розгорнути зображення в модальному режимі, натиснувши кнопку зміни маршруту /somePage/:imgId, вона прокрутить вгору :(. Будь-який спосіб "контролювати", чи слід стріляти OnUpdate подія на конкретних маршрутах / Params?
connected_user

Коли я спробував це, TypeScript поскаржився на те, onUpdateщо не існує реквізиту HashRouter ... Якщо хтось стикається з тією ж проблемою: я в кінцевому підсумку використовував рішення ScrollToTop, описане далі внизу (і в документах, що реагують на реакцію), що працювало ідеально для мене.
Ніколь

9

Для тих, хто використовує гачки, спрацює наступний код.

React.useEffect(() => {
  window.scrollTo(0, 0);
}, []);

Зауважте, ви також можете імпортувати useEffect безпосередньо: import { useEffect } from 'react'


1
Як []другий параметр означає, що це відбудеться лише під час першого візуалізації, ви пробували без?
Powderham

8

Ось ще один підхід, який дозволяє вибрати, до яких змонтованих компонентів потрібно повернути положення прокрутки вікна без масового дублювання ComponentDidUpdate / ComponentDidMount.

Наведений нижче приклад - обгортання компонента Blog з ScrollIntoView (), так що якщо маршрут зміниться, коли компонент Blog встановлений, HOC's ComponentDidUpdate оновить положення прокрутки вікна.

Ви можете так само легко перегорнути його на весь додаток, так що при будь-якій зміні маршруту він спричинить скидання вікна.

ScrollIntoView.js

import React, { Component } from 'react';
import { withRouter } from 'react-router';

export default WrappedComponent => {
  class ResetWindowScroll extends Component {
    componentDidUpdate = (prevProps) => {
      if(this.props.location !== prevProps.location) window.scrollTo(0,0);
    }

    render = () => <WrappedComponent {...this.props} />
  }
  return withRouter(ResetWindowScroll);
}

Routes.js

import React from 'react';
import { Route, IndexRoute } from 'react-router';

import App from '../components/App';
import About from '../components/pages/About';
import Blog from '../components/pages/Blog'
import Index from '../components/Landing';
import NotFound from '../components/navigation/NotFound';
import ScrollIntoView from '../components/navigation/ScrollIntoView';

 export default (
    <Route path="/" component={App}>
        <IndexRoute component={Index} />
        <Route path="/about" component={About} /> 
        <Route path="/blog" component={ScrollIntoView(Blog)} />
        <Route path="*" component={NotFound} />
    </Route>
);

Наведений вище приклад чудово працює, але якщо ви перейшли до цього react-router-dom, то ви можете спростити вище, створивши HOCкоманду, яка обгортає компонент.

Ще раз, ви також можете так само легко обернути його на свої маршрути (тільки зміна componentDidMountметоду до componentDidUpdateметоду прикладу коду , написаного вище, а також обгортання ScrollIntoViewз withRouter).

контейнери / ScrollIntoView.js

import { PureComponent, Fragment } from "react";

class ScrollIntoView extends PureComponent {
  componentDidMount = () => window.scrollTo(0, 0);

  render = () => this.props.children
}

export default ScrollIntoView;

компоненти / Home.js

import React from "react";
import ScrollIntoView from "../containers/ScrollIntoView";

export default () => (
  <ScrollIntoView>
    <div className="container">
      <p>
        Sample Text
      </p>
    </div>
  </ScrollIntoView>
);

ScrollIntoView.js дає мені таку помилку "невикористаний вираз, очікується призначення або виклик функції"
EX0MAK3R

@ EX0MAK3R - Оновлена ​​відповідь.
Метт Карлотта

7

Це єдине, що працювало для мене (з компонентом класу ES6):

componentDidMount() {
  ReactDOM.findDOMNode(this).scrollIntoView();
}

Так само. Я спробував усі інші рішення, і це єдине, що працювало на мене.
Ерік Джеймс

7

Я використовую реакційний роутер ScrollToTop Component, код якого описаний у документах про реакцію-маршрутизатор

https://reacttraining.com/react-router/web/guides/scroll-restoration/scroll-to-top

Я змінюю код у одному файлі Routes, після чого не потрібно змінювати код у кожному компоненті.

Приклад коду -

Крок 1 - створити компонент ScrollToTop.js

import React, { Component } from 'react';
import { withRouter } from 'react-router';

class ScrollToTop extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0)
    }
  }

  render() {
    return this.props.children
  }
}

export default withRouter(ScrollToTop)

Крок 2 - У файл App.js додайте компонент ScrollToTop після <Router

const App = () => (
  <Router>
    <ScrollToTop>
      <App/>
    </ScrollToTop>
  </Router>
)

дійсно гарне рішення! Якщо у вас є маршрути, просто виведіть їх у верхній частині маршрутів, але нижче Router. Мені не потрібно було міняти кожен компонент.
висип

5

Рішення гачка :

  • Створіть гачок ScrollToTop

    import { useEffect } from "react";
    import { withRouter } from "react-router-dom";

    const ScrollToTop = ({ children, location: { pathname } }) => {
      useEffect(() => {
        window.scrollTo({
          top: 0,
          left: 0,
          behavior: "smooth"
        });
      }, [pathname]);

      return children || null;
    };

    export default withRouter(ScrollToTop);
  • Оберніть свою програму

    <Router>
        <ScrollToTop>
           <App />
        </ScrollToTop>
    </Router>

Документація: https://reacttraining.com/react-router/web/guides/scroll-restoration


5

Використання гаків у функціональних компонентах, припускаючи оновлення компонента, коли відбувається оновлення результату реквізиту

import React, { useEffect } from 'react';

export const scrollTop = ({result}) => {
  useEffect(() => {
    window.scrollTo(0, 0);
  }, [result])
}

en.reactjs.org/docs/hooks-custom.html#extracting-a-custom-hook Не забудьте, ім'я гачка має починатися із словаuse
CrsCaballero

4

Все вищесказане не працювало для мене - не впевнений, чому, але:

componentDidMount(){
    document.getElementById('HEADER').scrollIntoView();
}

працював, де HEADER - ідентифікатор мого елемента заголовка


Я використовував гачок useEffect, але це чудово працювало для мене на проекті Гетсбі. Дякую!
jj0b

4

Якщо всі хочуть зробити щось просте, це рішення, яке буде працювати для всіх

додайте цю міні функцію

scrollTop()
{
    window.scrollTo({
        top: 0,
        behavior: "smooth"
    });
}

викличте функцію як наступну з нижнього колонтитула сторінки

<a className="scroll-to-top rounded" style={{display: "inline"}} onClick={this.scrollTop}>TOP</a>

якщо ви хочете додати сюди приємні стилі - це css

.scroll-to-top {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  text-align: center;
  color: #fff;
  background: rgba(90, 92, 105, 0.5);
  line-height: 46px;
}


фрагмент коду, здається, не працює. Але рішення працювало на мене. Дякую і привіт!
глобус

3

Я використовую React Hooks і хотів чогось повторного використання, але і те, що я міг би зателефонувати в будь-який час (а не відразу після надання).

// utils.js
export const useScrollToTop = (initialScrollState = false) => {
  const [scrollToTop, setScrollToTop] = useState(initialScrollState);

  useEffect(() => {
    if (scrollToTop) {
      setScrollToTop(false);
      try {
        window.scroll({
          top: 0,
          left: 0,
          behavior: 'smooth',
        });
      } catch (error) {
        window.scrollTo(0, 0);
      }
    }
  }, [scrollToTop, setScrollToTop]);

  return setScrollToTop;
};

Потім для використання гачка ви можете:

import { useScrollToTop } from 'utils';

const MyPage = (props) => {
  // initialise useScrollToTop with true in order to scroll on page load 
  const setScrollToTop = useScrollToTop(true);

  ...

  return <div onClick={() => setScrollToTop(true)}>click me to scroll to top</div>
}

Чудове рішення!
Нік

2

Якщо ви робите це для мобільних пристроїв , принаймні з хромом, ви побачите білу смужку внизу.

Це відбувається, коли рядок URL зникає. Рішення:

Змініть css на висоту / хв-висоту: 100% на висоту / хв-висоту: 100vh .

Документи розробника Google


1

Жодна з наведених відповідей наразі не працює для мене. Виявляється, .scrollToце не так широко сумісно, ​​як .scrollIntoView.

У нашому App.js, в componentWillMount()ми додали

this.props.history.listen((location, action) => {
        setTimeout(() => { document.getElementById('root').scrollIntoView({ behavior: "smooth" }) }, 777)
    })

Це єдине рішення, яке працює для нас універсально. root - це ідентифікатор нашого додатка. "Плавне" поведінка працює не в кожному браузері / пристрої. Тайм-аут 777 трохи консервативний, але ми завантажуємо багато даних на кожну сторінку, тому через тестування це було необхідно. Коротше 237 може працювати для більшості програм.


1

Я зіткнувся з цим питанням, створивши сайт з Гетсбі, посилання якого побудовано на версії маршрутизатора Reach. Здається дивним, що це модифікація, яку потрібно зробити, а не поведінку за замовчуванням.

У всякому разі, я спробував багато рішень вище, і єдине, що насправді працювало для мене, було:

document.getElementById("WhateverIdYouWantToScrollTo").scrollIntoView()

Я поклав це на useEffect, але ви можете так само легко ввести його в компонентDidMount або запустити його будь-яким іншим способом.

Не впевнений, чому window.scrollTo (0, 0) не працюватиме для мене (та інших).


0

Усі рішення говорять про додавання прокрутки на componentDidMountабо, componentDidUpdateале з DOM.

Я все це робив і не працював.

Отже, придумав інший спосіб, який працює для мене просто чудово.

Додано componentDidUpdate() { window.scrollTo(0, 0) } до заголовка, що міна поза <Switch></Switch>елементом. Просто безкоштовно в додатку. Працює.

Я також дізнався про якусь річ ScrollRestoration , але я зараз ледачий. А поки що збережу це "DidUpdate" способом.

Сподіваюся, це допомагає!

будь обережним


0

Цей код викликає плавне поведінка на свиті :

<div onClick={() => {
   ReactDOM.findDOMNode(this.headerRef)
      .scrollIntoView({behavior: "smooth"});
                }} 
  className='go-up-button' >
</div>

Ви можете передавати інші параметри всередині scrollIntoView () Можна використовувати наступний синтаксис:

element.scrollIntoView();
element.scrollIntoView(alignToTop); // Boolean parameter
element.scrollIntoView(scrollIntoViewOptions); // Object parameter

Додаткове вирівнюванняToTop - булеве значення:

If true, the top of the element will be aligned to the top of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "start", inline: "nearest"}. This is the default value.
If false, the bottom of the element will be aligned to the bottom of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "end", inline: "nearest"}.

scrollIntoViewOptions Необов’язково - об’єкт із такими властивостями:

*behavior* Optional
    Defines the transition animation.
    One of "auto", "instant", or "smooth". Defaults to "auto".
*block* Optional
    One of "start", "center", "end", or "nearest". Defaults to "center".
*inline* Optional
    One of "start", "center", "end", or "nearest". Defaults to "nearest".

Детальніше можна ознайомитись тут: документи MDN


0

Жодна з наведених відповідей наразі не працює для мене. Виявляється, .scrollToце не так широко сумісно, ​​як .scrollIntoView.

У нашому App.js, в componentWillMount()ми додали

    this.props.history.listen((location, action) => {
            setTimeout(() => { document.getElementById('root').scrollIntoView({ behavior: "smooth" }) }, 777)
        })

Це єдине рішення, яке працює для нас універсально. rootідентифікатор нашого додатка. "Плавне" поведінка працює не в кожному браузері / пристрої. Тайм-аут 777 трохи консервативний, але ми завантажуємо багато даних на кожну сторінку, тому через тестування це було необхідно. Коротше 237 може працювати для більшості програм.


0

Якщо я припускаю, що ви створюєте главу скажімо, книгу на сторінку, все, що вам потрібно зробити, - це додати це до свого коду. Це працювало для мене як магія.

    componentDidUpdate(prevProps) {
      if (prevProps.currentChapter !== this.props.currentChapter) {
        window.scrollTo(0, 0);
      }
    }

З цим вам не потрібно створювати посилання на компонент, що надається.



0

Ви можете використовувати, це працює для мене.

import React, { useEffect } from 'react';

useEffect(() => {
    const body = document.querySelector('#root');

    body.scrollIntoView({
        behavior: 'smooth'
    }, 500)

}, []);

-1

Щось подібне працювало для мене на компоненті:

<div ref="scroller" style={{height: 500, overflowX: "hidden", overflowY: "auto"}}>
      //Content Here
</div>

Тоді в будь-якій функції стосується оновлень:

this.refs.scroller.scrollTop=0

-1

Для мене нічого не працювало, окрім:

componentDidMount(){

    $( document ).ready(function() {
        window.scrollTo(0,0);
    });
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.