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

編集:React v16.8 +

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

2
これは私のために働いた唯一の解決策です。また、試してみました:ReactDOM.findDOMNode(this).scrollTop = 0 and componentDidMount(){this._div.scrollTop = 0} render(){return <div ref = {(ref)=> this._div = ref} />}
Michael Bushe

W3Schoolsによると、このソリューションは現在すべてのブラウザーでサポートされています。また、ReactDOMライブラリは、Reactの将来のバージョンで廃止される予定です。
BishopZ 2017年

2
@Tomasz-特定のdivをheightまたはmin-heightに設定しても、この問題が時々発生することがわかりました:100%。私は削除して、どちらかの親でそれを包むか、それはまだスクロールすることができ、ツリーの中にさらに移動しなければならなかった
ラセミ

2
これは私にとっては機能しましたが、componentDidMountでは機能しませんでした。状態の変更によってページが再レンダリングされるときにCDMが起動されない可能性があるためです。したがって、この呼び出しを置きます-window.scrollTo(0、0); -どこにいても、状態を変更します。
Puneet Lamba 2017

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/…
Joe Delgado

可能であれば、ReactDom.findDOMNode()は使用しないでください。代わりにrefを使用してください。ここにスムーズスクロールを使用した解決策を
bbrinx

default.a.createRefは関数ではありません
Anupam Maurya

48

このようなものを使用できます。ReactDomはreact.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 2017

findDOMNodeは、基になるDOMノードにアクセスするために使用されるエスケープハッチです。ほとんどの場合、このエスケープハッチはコンポーネントの抽象化を貫通するため、使用しないことをお勧めします。StrictModeでは非推奨になりました。reactjs.org/docs/react-dom.html
Vivek Kumar

16

React Routingでは、新しいルートにリダイレクトした場合、ページの上部に自動的に移動しないという問題があります。

私も同じ問題を抱えていました。

コンポーネントに1行追加したところ、バターのように機能しました。

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

参照:反応トレーニング


「トップにジャンプ」ボタンにこれを使用する場合、これは推奨される方法ですか?または、ウィンドウオブジェクトを使用しない「反応」方法がある場合
Toxnyc

1
通知をお寄せいただきありがとうございます。私が提供した解決策は、v5未満のreact-router domバージョンに適用できます。v4.2.2を使用していて、別のページに移動すると、デフォルトでは上部に表示されませんでした。ページなので、ナビゲーション後にユーザーを手動でページの上部に移動する必要がありますが、v5.0.1では、react-router domはスクロール復元を箱から出して出荷するのを停止しました。この機能はデフォルトであり、最新バージョンのreact-router-domでは、ナビゲーション後にページの上部に移動します。
Vishal Shetty

1
@Toxnycしたがって、ウィンドウオブジェクトの使用はJavaScriptと同じです。反応がJavascriptの上にある場合、バックグラウンドでReactプラグインのいずれかを使用しても、JavaScriptとウィンドウオブジェクトのみを使用します。私の知識によると、反応ドキュメントにはありません。ウィンドウ画面の詳細を取得できるもの。それを機能させるためには、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} />
    }
}

これはうまくいきます。ありがとう。明確にするために、私は自分のrenderステートメントの<div ref={(ref) => this._div = ref} />最初<div>にを入れました。残りのレンダリングはまったく同じです。
ジョシュF

スタイル付きコンポーネントを使用している場合は、「ref」の代わりに「innerRef」を使用する必要があります。
優れた

完全に動作します。私が取り組んでいたことについては、さらに簡単に<div ref="main">なりましたthis.refs.main.scrollTop=0
チャックファクトリー

2
文字列を使用したrefsの@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リンク


各コンポーネントがそれ自体を処理するのではなく、ルーターの小さなコード変更のみを必要とするエレガントなソリューション。<3
alengel

残念ながら、onUpdateは指定されたルートでルーティングされるすべての新しいrouteParamで起動します。たとえば、大量の画像があるページがあり、クリックしてルートをに変更したときに画像をモーダルで展開できる場合は/somePage/:imgId、上にスクロールします:(。発砲するかどうかを「制御」する方法特定のルート/パラメータのonUpdateイベント?
connected_user

これを試したところ、TypeScript onUpdateはHashRouterの小道具には存在しないと文句を言いました...誰かが同じ問題に遭遇した場合:後で説明するScrollToTopソリューション(およびreact-routerのドキュメント)を使用することになり、完全に機能しました。
ニコール

9

フックを使用する場合は、次のコードが機能します。

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

注:useEffectを直接インポートすることもできます。 import { useEffect } from 'react'


1
[]二番目のパラメータ手段としてそれだけで、最初のレンダリングに起こるのだろう、あなたはせずに試してみましたか?
Powderham

8

これは、ComponentDidUpdate / ComponentDidMountを大量に複製することなく、ウィンドウのスクロール位置をリセットするマウントされたコンポーネントを選択できる別のアプローチです。

以下の例は、BlogコンポーネントをScrollIntoView()でラップしているため、Blogコンポーネントがマウントされたときにルートが変更された場合、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

私はreact-routerのScrollToTopコンポーネントを使用していますが、コードはreact-routerのドキュメントに記載されています

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


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は私のヘッダー要素の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;
}


コードスニペットが機能していないようです。しかし、解決策は私のために働いた。ありがとう、そして乾杯!
グローブファイア

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

素晴らしい解決策!
Nick


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

Reach Routerの上にリンクが構築されているGatsbyでサイトを構築しているときにこの問題に遭遇しました。これは、デフォルトの動作ではなく、行う必要がある変更であることは奇妙に思われます。

とにかく、私は上記の解決策の多くを試しました、そして実際に私のために働いた唯一のものは:

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

これをuseEffectに入れましたが、componentDidMountに入れたり、他の方法でトリガーしたりできます。

window.scrollTo(0、0)が私(および他の人)に対して機能しない理由がわかりません。


0

すべてのソリューションは、スクロールをDOMに追加するcomponentDidMountcomponentDidUpdate、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

たとえば、ページごとに1冊の本をレンダリングしているとしたら、これをコードに追加するだけです。これは魔法のように私のために働いた。

    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.