Gulir ke bagian atas halaman setelah merender di react.js


168

Saya punya masalah, yang saya tidak punya ide, bagaimana menyelesaikannya. Dalam komponen reaksi saya, saya menampilkan daftar panjang data dan beberapa tautan di bagian bawah. Setelah mengklik salah satu tautan ini, saya mengisi daftar dengan koleksi tautan baru dan perlu menggulir ke atas.

Masalahnya adalah - bagaimana cara menggulir ke atas setelah koleksi baru diberikan?

'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;

Jawaban:


327

Akhirnya .. saya menggunakan:

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

EDIT: React v16.8 +

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

2
Ini hanya solusi yang bekerja untuk saya. Juga mencoba: ReactDOM.findDOMNode (ini) .scrollTop = 0 dan componentDidMount () {this._div.scrollTop = 0} render () {return <div ref = {(ref) => this._div = ref} />}
Michael Bushe

Menurut W3Schools, solusi ini saat ini didukung oleh semua browser. Pustaka ReactDOM juga tidak lagi digunakan dalam versi React yang akan datang.
BishopZ

2
@ Thomasz - Saya menemukan saya masih memiliki masalah ini kadang-kadang ketika saya memiliki divs tertentu diatur ke ketinggian atau min-tinggi: 100%. Saya harus menghapus dan membungkusnya dengan orangtua atau pindah lebih jauh ke pohon di mana ia masih bisa bergulir
rasemat

2
Ini bekerja untuk saya tetapi tidak di bawah componentDidMount, karena CDM mungkin tidak dipecat ketika keadaan perubahan menghasilkan rendering ulang halaman. Jadi panggilan ini - window.scrollTo (0, 0); - dimanapun Anda mengubah negara.
Puneet Lamba

4
Bagi mereka yang menggunakan kait, kode berikut ini akan berfungsi. React.useEffect(() => { window.scrollTo(0, 0); }, []); Catatan, Anda juga dapat mengimpor useEffect secara langsung:import { useEffect } from 'react'
Powderham

72

Karena solusi asli disediakan untuk versi reaksi paling awal , berikut ini adalah pembaruan:

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 === tidak terdefinisi
Dave Lunny

1
@ DaveLunny Anda mungkin bereaksi15? coba impor dan lakukan ReactDOM ReactDOM.findDOMNode(this).scrollTop = 0
Marcus Ericsson

12
this is undefined in arrow functionssalah. Kata kunci ini terikat dengan konteks yang sama dengan fungsi pengembang
Joe Delgado

Jika memungkinkan Anda harus menghindari ReactDom.findDOMNode (). Gunakan referensi sebagai gantinya. Saya memposting solusi menggunakan gulir halus di sini
bbrinx

default.a.createRef bukan fungsi
Anupam Maurya

48

Anda bisa menggunakan sesuatu seperti ini. ReactDom untuk react.14. Bereaksi sebaliknya.

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

Perbarui 5/11/2019 untuk 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)
    }
  }


Dari semua saran di halaman ini, ini adalah satu-satunya yang bekerja untuk saya.
Josh F

Catatan: jika componentDidUpdate tidak berfungsi untuk Anda, componentDidMountadalah alternatif lain.
Alex Fallenstedt

findDOMNode adalah pintu keluar yang digunakan untuk mengakses simpul DOM yang mendasarinya. Dalam kebanyakan kasus, penggunaan pintu darurat ini tidak disarankan karena menembus abstraksi komponen. Itu sudah ditinggalkan di StrictMode. reactjs.org/docs/react-dom.html
Vivek Kumar

16

Di Bereaksi Perutean ada masalah bahwa jika kita mengarahkan ulang ke rute baru, maka itu tidak akan secara otomatis membawa Anda ke bagian atas halaman.

Bahkan saya punya masalah yang sama.

Saya baru saja menambahkan satu baris ke komponen saya dan itu bekerja seperti mentega.

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

Rujuk: bereaksi pelatihan


apakah ini cara yang disarankan jika saya menggunakan ini untuk tombol 'lompat ke atas' saya? atau jika ada cara 'bereaksi' di mana kita tidak menggunakan objek jendela?
Toxnyc

1
Terima kasih telah menyampaikan pemberitahuan, solusi yang saya berikan berlaku untuk versi dom react-router kurang dari v5, saya menggunakan v4.2.2 dan di sana ketika Anda menavigasi ke halaman lain Anda tidak dibawa secara default ke bagian atas halaman, jadi kita harus secara manual membawa pengguna ke atas halaman setelah navigasi, tetapi dengan v5.0.1 dom router-router berhenti mengirim restorasi gulir keluar dari kotak, karena sesuai dokumen mereka mereka mengatakan bahwa browser mulai mendukung fitur ini secara default dan dengan versi terbaru dari router-dom Anda akan dibawa ke bagian atas halaman setelah navigasi.
Vishal Shetty

1
@ Toxnyc jadi menggunakan objek jendela adalah apa itu Javascript, Jika bereaksi di atas Javascript maka bahkan jika Anda menggunakan React Plugin di belakang layar itu akan menggunakan Javascript dan objek jendela saja, sesuai pengetahuan saya bereaksi dokumen tidak memiliki apa pun yang kita bisa mendapatkan detail layar jendela. kita harus menggunakan Javascript untuk membuatnya berfungsi.
Vishal Shetty

13

Ini bisa, dan mungkin harus, ditangani menggunakan referensi :

"... kamu bisa menggunakan ReactDOM.findDOMNode sebagai" escape hatch "tapi kami tidak merekomendasikannya karena itu merusak enkapsulasi dan dalam hampir setiap kasus ada cara yang lebih jelas untuk menyusun kode kamu dalam model React."

Kode contoh:

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

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

Ini sangat bagus. Terima kasih. Untuk lebih jelasnya, saya letakkan <div ref={(ref) => this._div = ref} />di bagian paling pertama <div>dari pernyataan render saya. Sisa render saya tetap sama persis.
Josh F

Jika Anda menggunakan komponen Style, Anda harus menggunakan "innerRef" alih-alih "ref". Solusi hebat
furcicm

Benar-benar bekerja. Untuk apa yang saya kerjakan, saya bisa lebih sederhana dengan <div ref="main">dan kemudianthis.refs.main.scrollTop=0
chuckfactory

2
@chuckfactory pengaturan referensi menggunakan string mungkin akan dihapus di beberapa titik, dan sebenarnya memiliki beberapa kelemahan menarik yang mungkin ingin Anda pelajari. news.ycombinator.com/edit?id=12093234
NJensen

10

Anda dapat melakukan ini di router seperti itu:

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

The onUpdate={() => window.scrollTo(0, 0)}menempatkan gulir atas. Untuk informasi lebih lanjut, periksa: tautan codepen


solusi elegan yang hanya membutuhkan perubahan kode kecil di router daripada meminta masing-masing komponen menanganinya sendiri. <3
alengel

Sayangnya onUpdate kebakaran dengan setiap routeParam baru dialihkan dalam rute yang diberikan. Jadi jika Anda misalnya memiliki halaman dengan banyak gambar, dan jika Anda dapat memperluas gambar dalam modal ketika diklik mengubah rute ke /somePage/:imgId, itu akan menggulir ke atas :(. Cara apa pun untuk "mengontrol" apakah akan memecat atau tidak acara onUpdate pada rute / params tertentu?
connected_user

Ketika saya mencoba ini, TypeScript mengeluh bahwa onUpdatetidak ada di props HashRouter ... Jika ada yang menemukan masalah yang sama: Saya akhirnya menggunakan solusi ScrollToTop yang dijelaskan lebih jauh ke bawah (dan dalam dokumen-dokumen router reaksi) yang bekerja dengan baik untuk saya.
Nicole

9

Bagi mereka yang menggunakan kait, kode berikut ini akan berfungsi.

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

Catatan, Anda juga dapat mengimpor useEffect secara langsung: import { useEffect } from 'react'


1
The []sebagai sarana parameter kedua hal itu hanya akan terjadi pada pertama render, apakah Anda mencoba tanpa?
Powderham

8

Berikut ini pendekatan lain yang memungkinkan Anda untuk memilih komponen yang dipasang yang Anda inginkan untuk mengatur ulang posisi gulir jendela tanpa menduplikasi MassalDidUpdate / ComponentDidMount.

Contoh di bawah ini adalah membungkus komponen Blog dengan ScrollIntoView (), sehingga jika rute berubah ketika komponen Blog dipasang, maka ComponentDidUpdate HOC akan memperbarui posisi gulir jendela.

Anda dapat dengan mudah membungkusnya di seluruh aplikasi, sehingga pada setiap perubahan rute, itu akan memicu pengaturan ulang jendela.

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

Contoh di atas berfungsi dengan baik, tetapi jika Anda telah bermigrasi ke react-router-dom, maka Anda dapat menyederhanakan di atas dengan membuat HOCyang membungkus komponen.

Sekali lagi, Anda bisa juga dengan mudah membungkusnya lebih rute Anda (hanya perubahan componentDidMountmetode untuk componentDidUpdatemetode contoh kode yang ditulis di atas, serta pembungkus ScrollIntoViewdengan withRouter).

wadah / ScrollIntoView.js

import { PureComponent, Fragment } from "react";

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

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

export default ScrollIntoView;

komponen / 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 memberi saya kesalahan berikut "ekspresi yang tidak digunakan, diharapkan penugasan atau panggilan fungsi"
EX0MAK3R

@ EX0MAK3R - Jawaban yang diperbarui.
Matt Carlotta

7

Ini adalah satu-satunya hal yang bekerja untuk saya (dengan komponen kelas ES6):

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

Juga. Saya mencoba semua solusi lain dan ini adalah satu-satunya yang bekerja untuk saya.
Erik James Robles

7

Saya menggunakan scrollToTop Component-router yang kode yang dijelaskan dalam docs-router Reaksi

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

Saya mengubah kode dalam file Routes tunggal dan setelah itu tidak perlu mengubah kode di setiap komponen.

Kode Contoh -

Langkah 1 - buat Komponen 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)

Langkah 2 - Dalam file App.js, tambahkan Komponen ScrollToTop setelah <Router

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

solusi yang sangat bagus! jika Anda memiliki rute, render di bagian atas rute Anda, tetapi di bawah Router.I tidak perlu mengubah setiap komponen.
ruam

5

Solusi kait :

  • Buat hook 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);
  • Bungkus Aplikasi Anda dengannya

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

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



4

Semua hal di atas tidak berhasil untuk saya - tidak yakin mengapa tetapi:

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

bekerja, di mana HEADER adalah id dari elemen header saya


Saya menggunakan hook useEffect tetapi ini bekerja baik untuk saya pada proyek Gatsby. Terima kasih!
jj0b

4

Jika semua yang ingin dilakukan adalah sesuatu yang sederhana di sini adalah solusi yang akan bekerja untuk semua orang

tambahkan fungsi mini ini

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

panggil fungsi sebagai berikut dari footer halaman

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

jika Anda ingin menambahkan gaya yang bagus di sini adalah 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;
}


snipet kode sepertinya tidak berfungsi. Tetapi solusinya bekerja untuk saya. Terima kasih dan tepuk tangan!
globefire

3

Saya menggunakan React Hooks dan menginginkan sesuatu yang dapat digunakan kembali tetapi juga sesuatu yang bisa saya hubungi kapan saja (bukan hanya setelah render).

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

Kemudian untuk menggunakan pengait bisa Anda lakukan:

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

Solusi bagus!
Nick

2

Jika Anda melakukan ini untuk seluler , setidaknya dengan chrome, Anda akan melihat bilah putih di bagian bawah.

Ini terjadi ketika bilah URL menghilang. Larutan:

Ubah css untuk tinggi / min-tinggi: 100% menjadi tinggi / min-tinggi: 100vh .

Google Developer Documents


1

Tidak ada jawaban di atas yang saat ini berfungsi untuk saya. Ternyata .scrollTotidak kompatibel secara luas .scrollIntoView.

Di App.js kami, di componentWillMount()kami tambahkan

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

Ini adalah satu-satunya solusi yang bekerja secara universal untuk kita. root adalah ID dari Aplikasi kami. Perilaku "smooth" tidak berfungsi di setiap browser / perangkat. Waktu tunggu 777 agak konservatif, tetapi kami memuat banyak data pada setiap halaman, jadi melalui pengujian ini diperlukan. 237 yang lebih pendek mungkin bekerja untuk sebagian besar aplikasi.


1

Saya mengalami masalah saat membangun situs dengan Gatsby yang Tautannya dibangun di atas Reach Router. Tampaknya aneh bahwa ini adalah modifikasi yang harus dibuat daripada perilaku default.

Lagi pula, saya mencoba banyak solusi di atas dan satu-satunya yang benar-benar bekerja untuk saya adalah:

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

Saya menempatkan ini di useEffect tetapi Anda bisa dengan mudah memasukkannya ke dalam componentDidMount atau memicunya dengan cara lain yang Anda inginkan.

Tidak yakin mengapa window.scrollTo (0, 0) tidak berfungsi untuk saya (dan lainnya).


0

Semua solusi berbicara tentang menambahkan gulir pada componentDidMountatau componentDidUpdatetetapi dengan DOM.

Saya melakukan semua itu dan tidak berhasil.

Jadi, menemukan beberapa cara lain yang berfungsi dengan baik untuk saya.

Ditambahkan componentDidUpdate() { window.scrollTo(0, 0) } pada tajuk, tambang itu keluar dari <Switch></Switch>elemen. Gratis di aplikasi. Bekerja

Saya juga menemukan tentang beberapa hal ScrollRestoration , tapi saya malas sekarang. Dan untuk sekarang akan tetap seperti itu "DidUpdate".

Semoga ini bisa membantu!

berhati-hatilah


0

Kode ini akan menyebabkan kelancaran pada gulungan :

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

Anda dapat melewatkan parameter lain di dalam scrollIntoView () Sintaks berikut dapat digunakan:

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

alignToTop Opsional Adalah nilai Boolean:

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 Opsional Adalah Objek dengan properti berikut:

*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".

Rincian lebih lanjut dapat ditemukan di sini: dokumen MDN


0

Tidak ada jawaban di atas yang saat ini berfungsi untuk saya. Ternyata .scrollTotidak kompatibel secara luas .scrollIntoView.

Di App.js kami, di componentWillMount()kami tambahkan

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

Ini adalah satu-satunya solusi yang bekerja secara universal untuk kita. rootadalah ID dari Aplikasi kami. Perilaku "smooth" tidak berfungsi di setiap browser / perangkat. Waktu tunggu 777 agak konservatif, tetapi kami memuat banyak data pada setiap halaman, jadi melalui pengujian ini diperlukan. 237 yang lebih pendek mungkin bekerja untuk sebagian besar aplikasi.


0

Jika saya berasumsi Anda membuat bab katakanlah, buku per halaman, yang perlu Anda lakukan adalah menambahkan ini ke kode Anda. Bagi saya ini seperti sulap.

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

Dengan ini, Anda tidak perlu membuat referensi pada komponen yang diberikan.


0

Inilah yang saya lakukan:

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

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

0

Anda dapat menggunakan, ini bekerja untuk saya.

import React, { useEffect } from 'react';

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

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

}, []);

-1

Sesuatu seperti ini bekerja untuk saya pada suatu komponen:

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

Kemudian dalam fungsi apa pun yang berhubungan dengan pembaruan:

this.refs.scroller.scrollTop=0

-1

Tidak ada yang berhasil untuk saya kecuali:

componentDidMount(){

    $( document ).ready(function() {
        window.scrollTo(0,0);
    });
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.