react-router her geçişte yukarı kaydır


126

Başka bir sayfaya geçerken sorun yaşıyorum, konumu önceki sayfadaki gibi kalacak. Böylece otomatik olarak en üste kaymayacaktır. Ben de kullanmayı denedim window.scrollTo(0, 0)üzerinde onChangeyönlendirici. Ben de scrollBehaviorbu sorunu düzeltirdim ama işe yaramadı. Bununla ilgili herhangi bir öneriniz var mı?


componentDidMountYeni güzergah bileşeninin mantığını yapamaz mısınız?
Yuya

Sadece eklemek document.body.scrollTop = 0;içinde componentDidMountsize geçiyorsunuz bileşenin
John Ruddell

@Kujira zaten componentDidMount () içine scrollTo ekledim ama işe yaramadı.
adrian hartanto

@JohnRuddell Bu da çalışmıyordu.
adrian hartanto

Çalışmak için document.getElementById ('root') kullanmalıyım. ScrollTop = 0
Bay 14

Yanıtlar:


131

React Router v4 belgeleri, kaydırma geri yüklemesi için kod örnekleri içerir . Aşağıda, bir sayfaya gidildiğinde "en üste kaydırmak" için site genelinde bir çözüm olarak hizmet veren ilk kod örnekleri verilmiştir:

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)

Ardından bunu uygulamanızın üst kısmında, ancak Yönlendiricinin altında oluşturun:

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

// or just render it bare anywhere you want, but just one :)
<ScrollToTop/>

^ doğrudan belgelerden kopyalanmıştır

Açıkçası bu çoğu durumda işe yarar, ancak sekmeli arayüzlerle nasıl başa çıkılacağı ve neden genel bir çözümün uygulanmadığı hakkında daha fazla bilgi var.


3
Yukarı kaydırırken aynı zamanda klavye odağını da sıfırlamalısınız. Bunu halletmek için bir şey yazdım: github.com/oaf-project/oaf-react-router
danielnixon

3
Dokümanlardan alınan bu alıntı Because browsers are starting to handle the “default case” and apps have varying scrolling needs (like this website!), we don’t ship with default scroll management. This guide should help you implement whatever scrolling needs you have.beni üzüyor, çünkü kod örnekleri vermek için kullandıkları tüm seçenekler, aslında özellik ayarları aracılığıyla kontrolün içine yerleştirilebilir ve varsayılan davranışla ilgili bazı kurallar daha sonra değiştirilebilir. Bu süper huysuz ve bitmemiş hissettiriyor, imho. Yalnızca gelişmiş tepki geliştiricilerinin yönlendirmeyi doğru bir şekilde yapabileceği ve #pitOfSuccess
kar kodu

2
oaf-react-router, work-aroundsburadaki herkesin göz ardı ettiği önemli erişilebilirlik sorunlarını ele alıyor gibi görünüyor . @Danielnixon için +100
snowcode

ScrollToTop tanımlı değil. App.js'de nasıl içe aktarılır? ScrollToTop'u './ScrollToTop'tan içe aktarma çalışmıyor.
anhtv13

@ anhtv13, bunu yeni bir soru olarak sormalısınız, böylece referans verdiğiniz kodu ekleyebilirsiniz.
mtl

110

ama sınıflar çok 2018

React Hooks ile ScrollToTop uygulaması

ScrollToTop.js

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

function ScrollToTop({ history }) {
  useEffect(() => {
    const unlisten = history.listen(() => {
      window.scrollTo(0, 0);
    });
    return () => {
      unlisten();
    }
  }, []);

  return (null);
}

export default withRouter(ScrollToTop);

Kullanım:

<Router>
  <Fragment>
    <ScrollToTop />
    <Switch>
        <Route path="/" exact component={Home} />
    </Switch>
  </Fragment>
</Router>

ScrollToTop ayrıca bir sarmalayıcı bileşeni olarak da uygulanabilir:

ScrollToTop.js

import React, { useEffect, Fragment } from 'react';
import { withRouter } from 'react-router-dom';

function ScrollToTop({ history, children }) {
  useEffect(() => {
    const unlisten = history.listen(() => {
      window.scrollTo(0, 0);
    });
    return () => {
      unlisten();
    }
  }, []);

  return <Fragment>{children}</Fragment>;
}

export default withRouter(ScrollToTop);

Kullanım:

<Router>
  <ScrollToTop>
    <Switch>
        <Route path="/" exact component={Home} />
    </Switch>
  </ScrollToTop>
</Router>

3
İnternette şimdiye kadar gördüğüm en iyi çözüm. Ben sadece biraz bir özellik katmıyor neden tepki-yönlendirici projeyi karıştı scrollToTopetmek <Route>. Çok sık kullanılan bir özellik gibi görünüyor.
stanleyxu2005

İyi iş ahbap. Çok yardımcı oldu.
VaibS

Bunu birim test etmenin uygun bir yolu ne olabilir?
Matt

kontrol etmelisiniz action !== 'POP'. Dinleyici, işlemi 2.
bağımsız

1
Ayrıca, withRouter HOC yerine useHistory kancasını da kullanabilirsiniz
Atombit

30

Bu cevap eski kod içindir, yönlendirici v4 için + diğer cevapları kontrol edin

<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}>
  ...
</Router>

Çalışmıyorsa, sebebini bulmalısın. Ayrıca içeridecomponentDidMount

document.body.scrollTop = 0;
// or
window.scrollTo(0,0);

kullanabilirsin:

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

"scrolled = false" gibi bir işaret ekleyebilir ve ardından güncellemede:

componentDidUpdate() {
  if(this.scrolled === false){
    window.scrollTo(0,0);
    scrolled = true;
  }
}

Yanıtı getDomNode olmadan güncelledim çünkü aslında bunu en üste kaydırmak için kullanmak zorunda kalmadım. Ben sadece kullanıyorumwindow.scrollTo(0,0);
Lukas Liesis

3
onUpdatereact-router
v4'te

@DragosRizescu Bu yöntemi onUpdatekanca olmadan kullanma konusunda herhangi bir rehberlik var mı?
Matt Voda

1
@MattVoda Tarihin kendisindeki değişiklikleri dinleyebilir, örnekleri kontrol edebilirsiniz: github.com/ReactTraining/history
Lukas Liesis

3
@MattVoda Eğer elde edebilirsiniz nasıl Aşağıda bir yanıt yazdı-yönlendirici-v4 tepki ile
Dragos Rizescu

28

İçin tepki-yönlendirici v4 : burada kaydırma restorasyon ulaşır bir create-tepki-uygulamasıdır http://router-scroll-top.surge.sh/ .

Bunu başarmak için Routebileşeni dekore edebilir ve yaşam döngüsü yöntemlerinden yararlanabilirsiniz:

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

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

  render() {
    const { component: Component, ...rest } = this.props;

    return <Route {...rest} render={props => (<Component {...props} />)} />;
  }
}

export default withRouter(ScrollToTopRoute);

Üzerinde componentDidUpdatekonum yol adının ne zaman değiştiğini kontrol edebilir ve bunu pathpervane ile eşleştirebiliriz ve eğer tatmin edildiyse, pencere kaydırmasını geri yükleyebiliriz.

Bu yaklaşımla ilgili harika olan şey, kaydırmayı geri yükleyen rotalara ve kaydırmayı geri yüklemeyen rotalara sahip olabilmemizdir.

App.jsYukarıdakileri nasıl kullanabileceğinize dair bir örnek:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Lorem from 'react-lorem-component';
import ScrollToTopRoute from './ScrollToTopRoute';
import './App.css';

const Home = () => (
  <div className="App-page">
    <h2>Home</h2>
    <Lorem count={12} seed={12} />
  </div>
);

const About = () => (
  <div className="App-page">
    <h2>About</h2>
    <Lorem count={30} seed={4} />
  </div>
);

const AnotherPage = () => (
  <div className="App-page">
    <h2>This is just Another Page</h2>
    <Lorem count={12} seed={45} />
  </div>
);

class App extends Component {
  render() {
    return (
      <Router>
        <div className="App">
          <div className="App-header">
            <ul className="App-nav">
              <li><Link to="/">Home</Link></li>
              <li><Link to="/about">About</Link></li>
              <li><Link to="/another-page">Another Page</Link></li>
            </ul>
          </div>
          <Route exact path="/" component={Home} />
          <ScrollToTopRoute path="/about" component={About} />
          <ScrollToTopRoute path="/another-page" component={AnotherPage} />
        </div>
      </Router>
    );
  }
}

export default App;

Yukarıdaki koddan, dikkat çekilmesi ilginç olan şey, yalnızca gezinirken /aboutveya /another-pageen üste kaydırma işleminin önceden gerçekleştirilmesidir. Ancak devam ederken, /kaydırma geri yüklemesi olmayacak.

Kod tabanının tamamı burada bulunabilir: https://github.com/rizedr/react-router-scroll-top


1
Tam da aradığım şey! ScrollToTopRoute'un componentDidMount'una scrollTo'yu eklemem gerekiyordu, çünkü rotalarım bir Switch bileşenine sarılmıştı (ayrıca her montajda ateşlenmesini istediğim için
if'i

ScrollToTopRoute işleminizde render = {props => (<Component {... props} />)} belirtmeniz gerekmez. Yalnızca rotada {... rest} kullanmak işe yarayacaktır.
Finickyflame

Bu cevap, bir çözüme ulaşmak ve hatamı düzeltmek için bana tüm araçları sağladı. Çok teşekkür ederim.
Null isTrue

Tamamen çalışmıyor. Proje bağlantısını takip ederseniz, o zaman varsayılan olarak Home. Şimdi sayfanın en altına Homegidin ve şimdi 'Başka Sayfa'ya gidin ve kaydırmayın. Şimdi tekrar gelirseniz Home, bu sayfa en üste kaydırılacaktır. Ancak cevabınıza göre homesayfa kaydırılmış halde tutulmalıdır.
aditya81070

18

onUpdate={() => window.scrollTo(0, 0)}Yöntemin modası geçmiş olduğu unutulmamalıdır .

İşte react-router 4+ için basit bir çözüm.

const history = createBrowserHistory()

history.listen(_ => {
    window.scrollTo(0, 0)  
})

<Router history={history}>

Geçmiş kullanılıyorsa bu doğru cevap olmalıdır. Şu anda bulunduğunuz sayfaya giden bir bağlantıya tıklamak da dahil olmak üzere tüm olasılıkları kapsar. Bulduğum tek sorun, scrollTo'nun ateşlenmemesi ve bir setTimeout (window.scrollTo (0, 0), 0); Hala nedenini anlamıyorum ama hey ho
sidonaldson

3
Eğer eklerken bir sorun yaşayabilirsiniz #ve ?bizim url sonuna. İlk durumda
Arseniy-II

1
Maalesef bu, BrowserRouter ile çalışmıyor.
VaibS

17

React 16.8+ çalıştırıyorsanız, her gezintide pencereyi yukarı kaydıracak bir bileşenle başa çıkmak kolaydır:
İşte scrollToTop.js bileşeninde

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

export default function ScrollToTop() {
  const { pathname } = useLocation();

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

  return null;
}

Ardından bunu uygulamanızın en üstünde, ancak Router'ın altında oluşturun.
İşte app.js'de

import ScrollToTop from "./scrollToTop";

function App() {
  return (
    <Router>
      <ScrollToTop />
      <App />
    </Router>
  );
}

veya index.js'de

import ScrollToTop from "./scrollToTop";

ReactDOM.render(
    <BrowserRouter>
        <ScrollToTop />
        <App />
    </BrowserRouter>
    document.getElementById("root")
);

Bu Çözümü beğendim, teşekkürler
Omar Hasan

11

Route bileşeninize ekleyebileceğiniz bir React Hook. useLayoutEffectÖzel dinleyiciler yerine kullanmak .

import React, { useLayoutEffect } from 'react';
import { Switch, Route, useLocation } from 'react-router-dom';

export default function Routes() {
  const location = useLocation();
  // Scroll to top if path changes
  useLayoutEffect(() => {
    window.scrollTo(0, 0);
  }, [location.pathname]);

  return (
      <Switch>
        <Route exact path="/">

        </Route>
      </Switch>
  );
}

Güncelleme : Daha az görsel şaka useLayoutEffectyerine kullanılmak üzere güncellendiuseEffect . Kabaca bu şu anlama gelir:

  • useEffect: bileşenleri oluştur -> ekrana boya -> yukarı kaydır (çalıştırma efekti)
  • useLayoutEffect: bileşenleri oluştur -> en üste kaydır (çalıştırma efekti) -> ekrana boya

Veri yüklüyor olmanıza (döndürücüleri düşünün) veya sayfa geçiş animasyonlarınız olup olmadığına bağlı olarak sizin için useEffectdaha iyi sonuç verebilir.


7

Uygulamamla aynı sorunu yaşadım.Aşağıdaki kod parçacığını kullanmak, bir sonraki düğmeyi tıkladığınızda sayfanın en üstüne gitmeme yardımcı oldu.

<Router onUpdate={() => window.scrollTo(0, 0)} history= {browserHistory}>
...
</Router>

Ancak, sorun tarayıcıda hala devam etti. Birçok denemeden sonra, bunun tarayıcı penceresinin geçmiş nesnesi olduğunu fark etti, bu da otomatik olarak ayarlanmış bir kaydırmaRestorasyon özelliğine sahip. Bunu manuel olarak ayarlamak sorunumu çözdü.

function scrollToTop() {
    window.scrollTo(0, 0)
    if ('scrollRestoration' in history) {
        history.scrollRestoration = 'manual';
    }
}

<Router onUpdate= {scrollToTop} history={browserHistory}>
....
</Router>

7

Aşağıdaki bir bileşende <Router>

Sadece bir React Hook ekleyin (bir React sınıfı kullanmıyorsanız)

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

5

react-router-dom v5Bu v4 çözümlerinden hiçbiri benim için işe yaramadığı için çözümümü kullananlar için paylaşmak istiyorum .

Sorunumu çözen şey, react-router-scroll-top'ı kurmak ve sarıcıyı şu şekilde koymaktı <App />:

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

ve bu kadar! işe yaradı!


4

Kancalar oluşturulabilir ve React Router v5.1'den beri bir kancamız var useHistory(). @ Zurfyx'in cevabına dayanarak, bu işlevsellik için yeniden kullanılabilir bir kanca oluşturdum:

// useScrollTop.ts
import { useHistory } from 'react-router-dom';
import { useEffect } from 'react';

/*
 * Registers a history listener on mount which
 * scrolls to the top of the page on route change
 */
export const useScrollTop = () => {
    const history = useHistory();
    useEffect(() => {
        const unlisten = history.listen(() => {
            window.scrollTo(0, 0);
        });
        return unlisten;
    }, [history]);
};

4

React hooks 2020 :)

import React, { useLayoutEffect } from 'react';
import { useLocation } from 'react-router-dom';

const ScrollToTop: React.FC = () => {
  const { pathname } = useLocation();
  useLayoutEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);

  return null;
};

export default ScrollToTop;

lütfen bu bölümü açıklar mısın? const ScrollToTop: React.FC = () => {Ne anlama ScrollToTop: React.FCgeldiğini anlamıyorum
beeftosino


3

Çözümüm: ekran bileşenlerimde kullandığım bir bileşen (en üste bir kaydırma yapmak istediğim yer).

import { useLayoutEffect } from 'react';

const ScrollToTop = () => {
    useLayoutEffect(() => {
        window.scrollTo(0, 0);
    }, []);

    return null;
};

export default ScrollToTop;

Bu, geri giderken kaydırma konumunu korur. UseEffect () kullanmak benim için sorunluydu, geri döndüğümde belge en üste kayıyordu ve zaten kaydırılmış bir belgede rota değiştirildiğinde göz kırpma etkisi yaratıyordu.


2

Adlı bir Yüksek Sipariş Bileşeni yazdım withScrollToTop. Bu HOC iki işarete sahiptir:

  • onComponentWillMount- Gezinme sırasında yukarıya kaydırılıp kaydırılmayacağı ( componentWillMount)
  • onComponentDidUpdate- Güncelleme ( componentDidUpdate) üzerine yukarı kaydırılıp kaydırılmayacağı . Bu bayrak, bileşenin çıkarılmadığı, ancak bir gezinme olayının meydana geldiği, örneğin - dan /users/1- arası durumlarda gereklidir /users/2.

// @flow
import type { Location } from 'react-router-dom';
import type { ComponentType } from 'react';

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

type Props = {
  location: Location,
};

type Options = {
  onComponentWillMount?: boolean,
  onComponentDidUpdate?: boolean,
};

const defaultOptions: Options = {
  onComponentWillMount: true,
  onComponentDidUpdate: true,
};

function scrollToTop() {
  window.scrollTo(0, 0);
}

const withScrollToTop = (WrappedComponent: ComponentType, options: Options = defaultOptions) => {
  return class withScrollToTopComponent extends Component<Props> {
    props: Props;

    componentWillMount() {
      if (options.onComponentWillMount) {
        scrollToTop();
      }
    }

    componentDidUpdate(prevProps: Props) {
      if (options.onComponentDidUpdate &&
        this.props.location.pathname !== prevProps.location.pathname) {
        scrollToTop();
      }
    }

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

export default (WrappedComponent: ComponentType, options?: Options) => {
  return withRouter(withScrollToTop(WrappedComponent, options));
};

Kullanmak için:

import withScrollToTop from './withScrollToTop';

function MyComponent() { ... }

export default withScrollToTop(MyComponent);

1

İşte başka bir yöntem.

İçin tepki-yönlendirici v4 Eğer geçmiş olayı değişikliğine bağlamak bir dinleyici de can, aşağıdaki şekilde:

let firstMount = true;
const App = (props) => {
    if (typeof window != 'undefined') { //incase you have server-side rendering too             
        firstMount && props.history.listen((location, action) => {
            setImmediate(() => window.scrollTo(0, 0)); // ive explained why i used setImmediate below
        });
        firstMount = false;
    }

    return (
        <div>
            <MyHeader/>            
            <Switch>                            
                <Route path='/' exact={true} component={IndexPage} />
                <Route path='/other' component={OtherPage} />
                // ...
             </Switch>                        
            <MyFooter/>
        </div>
    );
}

//mounting app:
render((<BrowserRouter><Route component={App} /></BrowserRouter>), document.getElementById('root'));

Kaydırma düzeyi setImmediate(), rota bir bağlantıya tıklanarak değiştirilirse de 0'a ayarlanacaktır, ancak kullanıcı tarayıcıda geri düğmesine basarsa, tarayıcı geri düğmesine basıldığında kaydırma düzeyini manuel olarak önceki düzeye sıfırladığı için çalışmayacaktır. , bu yüzden kullanarak, setImmediate()tarayıcı kaydırma düzeyini sıfırladıktan sonra işlevimizin yürütülmesini sağlarız ve böylece bize istenen etkiyi veririz.


1

React yönlendirici dom v4 ile kullanabilirsiniz

aşağıdaki gibi bir scrollToTopComponent bileşeni oluşturun

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)

veya sekmeler kullanıyorsanız aşağıdaki gibi bir şey kullanın

class ScrollToTopOnMount extends Component {
    componentDidMount() {
      window.scrollTo(0, 0)
    }

    render() {
      return null
    }
}

class LongContent extends Component {
    render() {
      <div>
         <ScrollToTopOnMount/>
         <h1>Here is my long content page</h1>
      </div>
    }
}

// somewhere else
<Route path="/long-content" component={LongContent}/>

umarım bu, kaydırma restorasyonu hakkında daha fazla bilgi için yardımcı olur, docs hare react router dom scroll restoration


0

Bunun ReactDOM.findDomNode(this).scrollIntoView()işe yaradığını buldum . İçine yerleştirdim componentDidMount().


1
fark edilmeden değişebilecek belgelenmemiş dahili şeylerdir ve kodunuz çalışmayı durdurur.
Lukas Liesis

0

1-4 yol içeren daha küçük uygulamalar için, yalnızca bir yol yerine #id ile en üst DOM öğesine yeniden yönlendirerek onu kırmayı deneyebilirsiniz. O zaman ScrollToTop'ta Rotaları sarmaya veya yaşam döngüsü yöntemlerini kullanmaya gerek yoktur.


0

Sizde router.js, sadece routernesneye bu işlevi ekleyin . Bu işi yapacak.

scrollBehavior() {
        document.getElementById('app').scrollIntoView();
    },

Bunun gibi,

**Routes.js**

import vue from 'blah!'
import Router from 'blah!'

let router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    scrollBehavior() {
        document.getElementById('app').scrollIntoView();
    },
    routes: [
            { url: "Solar System" },
            { url: "Milky Way" },
            { url: "Galaxy" },
    ]
});

0

Bu, önceki yazılarda başkalarının yaptıklarına dayanan yaklaşımımdı. Yeniden oluşturmaları önlemek için konumu bağımlılık olarak kullanmanın 2020'de iyi bir yaklaşım olup olmayacağını mı merak ediyorsunuz?

import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

function ScrollToTop( { children } ) {
    let location = useLocation();

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

    return children
}

-1
render() {
    window.scrollTo(0, 0)
    ...
}

Desteklerin değiştirilmemesi ve componentDidUpdate () 'in ateşlenmemesi durumunda basit bir çözüm olabilir.


-11

Bu hileli (ama işe yarıyor): Sadece ekliyorum

window.scrollTo (0,0);

işlemek için();


2
bu nedenle, gezinme değiştiğinde değil, durum her değiştiğinde ve yeniden oluşturma gerçekleştiğinde yukarı kaydırılır. Cevabımı kontrol et
Lukas Liesis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.