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)
}

편집 : 반응 v16.8 +

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

2
이것은 나를 위해 일한 유일한 해결책입니다. 또한 시도 : ReactDOM.findDOMNode (this) .scrollTop = 0 및 componentDidMount () {this._div.scrollTop = 0} render () {return <div ref = {(ref) => this._div = ref} />}
Michael Bushe

W3Schools에 따르면이 솔루션은 현재 모든 브라우저에서 지원됩니다. 또한 ReactDOM 라이브러리는 향후 React 버전에서 더 이상 사용되지 않습니다.
BishopZ

2
@Tomasz-특정 div가 높이 또는 최소 높이로 설정된 경우에도 여전히이 문제가 있음을 알았습니다 .100 %. 나는 제거하고 두 부모에 포장 어디서 여전히 수 스크롤 트리에 추가로 이동했다
라 세미

2
상태 변경으로 인해 페이지가 다시 렌더링 될 때 CDM이 실행되지 않을 수 있기 때문에 componentDidMount에서는 작동하지 않았습니다. 따라서이 호출을 넣으십시오-window.scrollTo (0, 0); 어디에서나 상태를 변경할 수 있습니다.
푸네 람바

4
후크를 사용하는 사람들에게는 다음 코드가 작동합니다. React.useEffect(() => { window.scrollTo(0, 0); }, []); useEffect를 직접 가져올 수도 있습니다.import { useEffect } from 'react'
Powderham

72

원래 솔루션은 매우 초기 버전의 react 에 제공 되었으므로 다음은 업데이트입니다.

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
Dave Lunny

1
@DaveLunny 당신은 react15에있을 수 있습니까? ReactDOM을 가져 와서 시도해보십시오 ReactDOM.findDOMNode(this).scrollTop = 0
Marcus Ericsson

12
this is undefined in arrow functions부정확하다. this 키워드는 둘러싸는 함수와 같은 컨텍스트에 바인딩 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(); }

React 16+ 용 2019 년 5 월 11 일 업데이트

  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)
    }
  }


이 페이지의 모든 제안 중 이것이 나에게 적합한 유일한 제안입니다.
Josh F

참고 : componentDidUpdate가 작동하지 않으면 componentDidMount다른 대안입니다.
Alex Fallenstedt

findDOMNode는 기본 DOM 노드에 액세스하는 데 사용되는 이스케이프 해치입니다. 대부분의 경우이 탈출 해치는 구성 요소 추상화를 뚫기 때문에 사용하지 않는 것이 좋습니다. StrictMode에서는 더 이상 사용되지 않습니다. reactjs.org/docs/react-dom.html
Vivek Kumar

16

React Routing에는 새로운 경로로 리디렉션하면 자동으로 페이지 상단으로 이동하지 않는 문제가 있습니다.

심지어 나는 같은 문제가 있었다.

방금 구성 요소에 단일 행을 추가했으며 버터처럼 작동했습니다.

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

참조 : 훈련 반응


'맨 위로 이동'버튼에 이것을 사용하는 경우 이것이 권장되는 방법입니까? 또는 우리가 윈도우 객체를 사용하지 않는 '반응적인'방법이 있다면?
Toxnyc

1
공지 사항을 가져 주셔서 감사합니다. 내가 제공 한 솔루션은 v5 미만의 반응 라우터 dom 버전에 적용 가능하며 v4.2.2를 사용하고 있으며 다른 페이지로 이동하면 기본적으로 맨 위로 이동하지 않았습니다. 탐색 후 사용자를 페이지 맨 위로 수동으로 이동해야하지만 v5.0.1 반응 라우터 dom을 사용하면 문서에서 브라우저가 지원을 시작한다고 말하면서 상자에서 스크롤 복원을 전달하지 않습니다. 이 기능은 기본적으로 최신 버전의 react-router-dom으로 탐색 후 페이지 상단으로 이동합니다.
Vishal Shetty

1
@Toxnyc는 창 객체를 사용하는 것이 Javascript입니다. 반응이 Javascript 위에있는 경우 React Plugin을 장면 뒤에서 사용하더라도 지식 문서에 따라 Javascript 및 창 객체 만 사용합니다. 창 화면의 세부 정보를 얻을 수있는 모든 것 우리는 자바 스크립트와 함께 작동해야합니다.
Vishal Shetty

13

이것은 refs를 사용하여 처리 할 수 ​​있으며 아마도 처리해야합니다 .

"... 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>렌더 진술을 넣었다 . 내 렌더의 나머지 부분은 정확히 동일하게 유지됩니다.
Josh F

스타일 컴포넌트를 사용하는 경우 "ref"대신 "innerRef"를 사용해야합니다. 훌륭한 해결책
furcicm

완전히 작동합니다. 내가 작업 한 것을 들어, 난과 간단 할 수 <div ref="main">다음과this.refs.main.scrollTop=0
chuckfactory

2
문자열을 사용하여 @chuckfactory 설정 참조는 언젠가는 제거 될 것이며 실제로 배우고 싶은 흥미로운 단점이 있습니다. 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 link


각 구성 요소가 자체적으로 처리하지 않고 라우터에서 약간의 코드 변경 만 필요한 우아한 솔루션입니다. <3
alengel

불행하게도 onUpdate는 주어진 모든 경로에서 경로가 지정된 모든 새로운 routeParam과 함께 발생합니다. 따라서 예를 들어 이미지가 많은 페이지가 있고 경로를로 변경하면 클릭하면 모달로 이미지를 확장 할 수 있으면 /somePage/:imgId위로 스크롤됩니다. (. 특정 라우트 / 매개 변수에 대한 onUpdate 이벤트?
connected_user

이것을 시도했을 때 TypeScript onUpdate는 HashRouter의 props에 존재하지 않는다고 불평 했습니다.
Nicole

9

후크를 사용하는 사람들에게는 다음 코드가 작동합니다.

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

useEffect를 직접 가져올 수도 있습니다. import { useEffect } from 'react'


1
[]두 번째 매개 변수의 수단으로는 첫째, 당신이없이 시도 렌더링에 일어날 것인가?
Powderham

8

ComponentDidUpdate / ComponentDidMount를 대량 복제하지 않고 창 스크롤 위치를 재설정 할 마운트 된 구성 요소를 선택할 수있는 또 다른 방법이 있습니다.

아래 예제는 블로그 구성 요소를 ScrollIntoView ()로 랩핑하여 블로그 구성 요소가 마운트 될 때 경로가 변경되면 HOC의 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;

components / 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-업데이트 된 답변입니다.
Matt Carlotta

7

이것이 나를 위해 일한 유일한 것입니다 (ES6 클래스 구성 요소 사용).

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

마찬가지로. 나는 다른 모든 솔루션을 시도했지만 이것이 나를 위해 일한 유일한 솔루션입니다.
Erik James Robles

7

반응 라우터 문서에 설명 된 코드가 반응 라우터 ScrollToTop 구성 요소를 사용하고 있습니다.

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

정말 좋은 해결책! 경로가 있으면 경로의 상단에 있지만 라우터 아래에 렌더링하면 모든 단일 구성 요소를 변경할 필요가 없습니다.
발진

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



4

위의 모든 것이 나를 위해 작동하지 않았습니다. 왜 그런지 확실하지 않지만 :

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

HEADER는 내 헤더 요소의 ID입니다.


useEffect 후크를 사용했지만 Gatsby 프로젝트에서 효과적이었습니다. 감사!
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;
}


코드 스 니펫이 작동하지 않는 것 같습니다. 그러나 해결책은 나를 위해 일했습니다. 감사와 건배!
globefire

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 표시 줄이 사라지면 발생합니다. 해결책:

height / min-height : 100 % 의 CSS 를 height / min-height : 100vh로 변경하십시오 .

Google 개발자 문서


1

위의 답변 중 어느 것도 현재 나를 위해 일하지 않습니다. 그것 .scrollTo만큼 널리 호환되지 않는 것으로 나타났습니다 .scrollIntoView.

App.js에서 componentWillMount()우리는

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

이것은 우리를 위해 보편적으로 작동하는 유일한 솔루션입니다. root는 우리 앱의 ID입니다. "부드러운"동작은 모든 브라우저 / 장치에서 작동하지 않습니다. 777 시간 초과는 약간 보수적이지만 모든 페이지에 많은 데이터를로드하므로 테스트를 통해이 작업이 필요했습니다. 대부분의 응용 프로그램에서 더 짧은 237이 작동 할 수 있습니다.


1

이 문제는 Gatsby를 통해 링크가 Reach Router 위에 구축 된 사이트를 구축하는 데 문제가있었습니다. 이것이 기본 동작이 아닌 수정되어야하는 것이 이상해 보입니다.

어쨌든, 위의 많은 솔루션을 시도했지만 실제로 나를 위해 일한 유일한 솔루션은 다음과 같습니다.

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

이것을 useEffect에 넣었지만 componentDidMount에 쉽게 넣거나 원하는 다른 방법으로 트리거 할 수 있습니다.

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

alignToTop 선택 부울 값입니다.

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우리 앱의 ID입니다. "부드러운"동작은 모든 브라우저 / 장치에서 작동하지 않습니다. 777 시간 초과는 약간 보수적이지만 모든 페이지에 많은 데이터를로드하므로 테스트를 통해이 작업이 필요했습니다. 대부분의 응용 프로그램에서 더 짧은 237이 작동 할 수 있습니다.


0

내가 페이지 당 책 한 장을 렌더링한다고 가정하면, 코드에 이것을 추가하기 만하면됩니다. 이것은 마술처럼 나를 위해 일했습니다.

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

이를 통해 렌더링 할 구성 요소에 대한 참조를 만들 필요가 없습니다.


0

이것이 내가 한 일입니다.

...
useEffect(() => ref.current.scrollTo(0, 0));
const ref = useRef()

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

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);
    });
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.