Webエンジニアの備忘録

およそ自己の作業メモとして残しております。

react-router画面遷移時のスクロール位置を操作する

前のページのスクロール位置が残る

react-routerはURLのハッシュを用いて画面遷移を表現していますが、実際のルーティングは固定だったりします。

なので、こんな気遣いをしないと遷移後に最上部にスクロールしてくれなかったりします。

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

新しいプロジェクトを作成したときに、どうやってたっけ?と思ってしまったのでメモがてら残しておきます(^_^;)


ちなみに、ルーティングにパラメータを付けて、デフォルトのスクロール位置を変更させたい時はこちらのような共用モジュールを作成して対処しています。

自分の位置を返すComponent

import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class Scroller extends Component {
  componentDidMount() {
    const { active, callback } = this.props;

    if (active) {
      callback(this.scroller.offsetTop);
    }
  }
  componentWillUnmount() {
    this.scroller = null;
  }
  render() {
    return (
      <div ref={e => (this.scroller = e)} />
    );
  }
}
Scroller.propTypes = {
  active: PropTypes.bool,
  callback: PropTypes.func,
};
Scroller.defaultProps = {
  active: false,
  callback: null,
};

Scrollerはスクロールさせたい位置にマーカー的に配置します。

activeの場合のみコールバックで自分の位置を返します。

使い方はこんな感じです。

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import Scroller from './Scroller';

export default class Clips extends Component {
  componentDidUpdate() {
    if (this.position) {
      window.scrollTo(0, this.position);
      this.position = null;
    }
  }
  render() {
    const { location } = this.props;

    return (
      <div>
        <Scroller
          active={location.query.content === 'content1'}
          callback={e => (this.position = e)}
        />
        <div>
          コンテンツ1
        </div>
        <Scroller
          active={location.query.content === 'content2'}
          callback={e => (this.position = e)}
        />
        <div>
          コンテンツ2
        </div>
      </div>
    );
  }
}
Clips.propTypes = {
  location: PropTypes.shape().isRequired,
};

ルーティングに併せてスクロールできるパッケージもありますね。 こちらは座標指定が必要なので、併せて利用できるかと思います。 www.npmjs.com