別のページに移動すると問題が発生します。その位置は以前のページと同じままです。したがって、自動的に上にスクロールすることはありません。window.scrollTo(0, 0)
onChangeルーターでも使用してみました。この問題を修正するためにscrollBehaviorも使用しましたが、機能しませんでした。これについて何か提案はありますか?
document.body.scrollTop = 0;
でcomponentDidMount
あなたが移動している部品の
別のページに移動すると問題が発生します。その位置は以前のページと同じままです。したがって、自動的に上にスクロールすることはありません。window.scrollTo(0, 0)
onChangeルーターでも使用してみました。この問題を修正するためにscrollBehaviorも使用しましたが、機能しませんでした。これについて何か提案はありますか?
document.body.scrollTop = 0;
でcomponentDidMount
あなたが移動している部品の
回答:
React Router v4のドキュメントには、スクロール復元のためのコードサンプルが含まれています。これが最初のコードサンプルです。これは、ページに移動したときに「上にスクロール」するためのサイト全体のソリューションとして機能します。
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)
次に、アプリの上部、ただしルーターの下にレンダリングします。
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
// or just render it bare anywhere you want, but just one :)
<ScrollToTop/>
明らかにこれはほとんどの場合に機能しますが、タブ付きのインターフェースを処理する方法と、一般的なソリューションが実装されていない理由についての詳細があります。
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.
コード例を提供するために続くすべてのオプションが、実際にはプロパティ設定を介してコントロールに焼き付けられ、デフォルトの動作に関するいくつかの規則が変更される可能性があるため、悲しくなります。これはすごくハックで未完成な感じです。高度なリアクション開発者のみが適切にルーティングを実行でき、#pitOfSuccessを実行できないことを意味します
work-arounds
ここで無視されいるいるようです。+ danielnixonの+100
しかしクラスは2018年です
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);
使用法:
<Router>
<Fragment>
<ScrollToTop />
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</Fragment>
</Router>
ScrollToTopは、ラッパーコンポーネントとして実装することもできます。
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);
使用法:
<Router>
<ScrollToTop>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</ScrollToTop>
</Router>
scrollToTop
を追加しない理由を少し混乱しました<Route>
。非常によく使われる機能のようです。
この回答はレガシーコード用です。ルーターv4 +の場合は他の回答を確認してください
<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}>
...
</Router>
それが機能しない場合は、理由を見つける必要があります。また中componentDidMount
document.body.scrollTop = 0;
// or
window.scrollTo(0,0);
あなたは使うことができます:
componentDidUpdate() {
window.scrollTo(0,0);
}
"scrolled = false"のようないくつかのフラグを追加し、次に更新で追加できます:
componentDidUpdate() {
if(this.scrolled === false){
window.scrollTo(0,0);
scrolled = true;
}
}
window.scrollTo(0,0);
onUpdate
フックはreact-router v4で非推奨になりました-それを指摘したいだけです
onUpdate
フックなしでこのメソッドを使用するためのガイダンスはありますか?
以下のために反応し、ルータV4:、ここにスクロール復元実現作成反応するアプリですhttp://router-scroll-top.surge.sh/が。
これを実現するには、Route
コンポーネントを装飾し、ライフサイクルメソッドを活用します。
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);
で componentDidUpdate
、場所のパス名がいつ変更されたかを確認し、それをpath
小道具とさせます。問題がなければ、ウィンドウのスクロールを元に戻します。
このアプローチのクールな点は、スクロールを復元するルートとスクロールを復元しないルートを設定できることです。
ここでApp.js
あなたは上記を使用する方法の例:
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;
上記のコードから、興味深いのは、ナビゲートするとき、/about
または/another-page
トップへのスクロールアクションが実行されるときだけです。ただし、進行中/
スクロール復元を実行すると、復元は行わません。
コードベース全体は次の場所にあります:https : //github.com/rizedr/react-router-scroll-top
Home
。の一番下までスクロールして、Home
「AnotherPage」に移動し、スクロールしないでください。再びにHome
アクセスすると、このページが一番上までスクロールされます。しかし、あなたの答えによると、home
ページはスクロールされ続ける必要があります。
onUpdate={() => window.scrollTo(0, 0)}
メソッドが古いことに注意してください。
以下は、react-router 4+の簡単なソリューションです。
const history = createBrowserHistory()
history.listen(_ => {
window.scrollTo(0, 0)
})
<Router history={history}>
#
と、問題が発生します?
。最初のケースでは、一番上までスクロールしないでください。2番目のケースでは、スクロールしないでください。
React 16.8以降を実行している場合、これは、ナビゲーションごとにウィンドウを上にスクロールするコンポーネントで処理するのが簡単です。これは
scrollToTop.jsコンポーネントにあります。
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;
}
次に、アプリの上部に表示します
が、ルーターの下はapp.jsにあります
import ScrollToTop from "./scrollToTop";
function App() {
return (
<Router>
<ScrollToTop />
<App />
</Router>
);
}
またはindex.jsで
import ScrollToTop from "./scrollToTop";
ReactDOM.render(
<BrowserRouter>
<ScrollToTop />
<App />
</BrowserRouter>
document.getElementById("root")
);
私のアプリケーションでも同じ問題が発生しました。次のコードスニペットを使用すると、[次へ]ボタンをクリックしたときにページの上部にスクロールするのに役立ちました。
<Router onUpdate={() => window.scrollTo(0, 0)} history= {browserHistory}>
...
</Router>
ただし、問題はブラウザのバックでも引き続き発生しました。多くの試行の後、これはautoに設定されたscrollRestorationプロパティを持つブラウザウィンドウの履歴オブジェクトが原因であることがわかりました。これを手動に設定すると問題が解決しました。
function scrollToTop() {
window.scrollTo(0, 0)
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
}
<Router onUpdate= {scrollToTop} history={browserHistory}>
....
</Router>
以下のコンポーネントで <Router>
Reactフックを追加するだけです(Reactクラスを使用していない場合)
React.useEffect(() => {
window.scrollTo(0, 0);
}, [props.location]);
使用している人のために私のソリューションを共有したい react-router-dom v5
これらのv4ソリューションはどれも私のために機能しなかったので、てます。
私の問題を解決したのは、react-router-scroll-topをインストールして、次の<App />
ようにラッパーを配置することでした。
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
以上です!出来た!
フックはコンポーザブルであり、React Router v5.1以降、useHistory()
フックがあります。@zurfyxの回答に基づいて、この機能のために再利用可能なフックを作成しました。
// 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]);
};
Routeコンポーネントに追加できるReactフック。useLayoutEffect
カスタムリスナーの代わりに使用します。
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>
);
}
更新:ビジュアルジャンクを減らすためuseLayoutEffect
にuseEffect
、の代わりに使用するように更新されました。おおよそこれは次のように変換されます:
useEffect
:コンポーネントをレンダリング->画面にペイント->最上部にスクロール(実行効果)useLayoutEffect
:レンダリングコンポーネント->トップにスクロール(実行効果)->画面にペイントデータを読み込むか(スピナーを考える)、またはページ遷移アニメーションがあるかによって、useEffect
より適切に機能する場合があります。
Reactフック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;
const ScrollToTop: React.FC = () => {
わかりScrollToTop: React.FC
と呼ばれる高次コンポーネントを作成しましたwithScrollToTop
。このHOCは2つのフラグを受け取ります。
onComponentWillMount
-ナビゲーション時に上にスクロールするかどうか(componentWillMount
)onComponentDidUpdate
-更新時に上にスクロールするかどうか(componentDidUpdate
)。このフラグは、コンポーネントがアンマウントされていないが、ナビゲーションイベントが発生した場合(たとえば、から)に/users/1
必要/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));
};
それを使用するには:
import withScrollToTop from './withScrollToTop';
function MyComponent() { ... }
export default withScrollToTop(MyComponent);
私のソリューション:画面コンポーネントで使用しているコンポーネント(上にスクロールしたい場合)。
import { useLayoutEffect } from 'react';
const ScrollToTop = () => {
useLayoutEffect(() => {
window.scrollTo(0, 0);
}, []);
return null;
};
export default ScrollToTop;
これにより、戻るときにスクロール位置が保持されます。useEffect()の使用はバグが多く、戻ったときにドキュメントが上にスクロールし、既にスクロールしたドキュメントでルートが変更されたときに点滅効果もありました。
ここに別の方法があります。
以下のために反応し、ルータV4あなたはまた、次のようにして、歴史のイベントの変化にリスナーをバインドすることができます。
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'));
setImmediate()
リンクをクリックしてルートを変更した場合、スクロールレベルも0に設定されますが、ユーザーがブラウザーの戻るボタンを押すと、ブラウザーが戻るボタンを押したときに手動でスクロールレベルを前のレベルにリセットするため、スクロールレベルは機能しません。を使用setImmediate()
することで、ブラウザーがスクロールレベルをリセットし終えた後に関数が実行され、目的の効果が得られます。
React router dom v4で使用できます
以下のようなscrollToTopComponentコンポーネントを作成します
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)
または、タブを使用している場合は、以下のようなものを使用します
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}/>
これはドキュメントがHAREそこにスクロール復元VISTの詳細のために役に立てば幸いルータのDOMスクロールの復元を反応させます
私はそれReactDOM.findDomNode(this).scrollIntoView()
が働いていることを発見しました。中に入れましたcomponentDidMount()
。
render() {
window.scrollTo(0, 0)
...
}
小道具が変更されず、componentDidUpdate()が起動しない場合の簡単な解決策になります。
あなたにはrouter.js
、ただでこの機能を追加しrouter
たオブジェクト。これでうまくいきます。
scrollBehavior() {
document.getElementById('app').scrollIntoView();
},
このような、
**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" },
]
});
これはハッキーです(ただし動作します):追加するだけです
window.scrollTo(0,0);
render();
componentDidMount
新しいルートのコンポーネントのロジックを実行できませんか?