【React】HashRouter+Material UIでナビゲーションバーのselectedを制御する




背景

CakePHP4とReactで開発しているのですが、Browser Routerを使うとリロードしてしまったときにエラーが出てしまうのでHash Routerを使っています。ナビゲーションバーは以下のようにmaterial UIというライブラリで作成しているのですが、以下のような問題が起きていました。

ホーム画面以外のページ(画面A)でページ更新を行うと、ページ自体は画面Aが表示されているにも関わらず、Material UIのTabsが初期化されてホーム画面を指し示してしまう

例えば、URLがlocalhost/#/profileを示している時にリロードすると、ページ自体はプロフィールページが表示されているのにTabsではHomeが選択された状態で表示されるということです。

対処法

結論から言うと、現在どのページが選択されているかという設定値は<Tabs>コンポーネントのvalueというプロパティで制御されているので、コンポーネントの読み込み時にハッシュを拾ってvalueを変更する関数を書きます。下記の例ではHookを利用しているのでuseEffectで実施しています。Hookを利用しない場合は、componentDidMount()で行えば動くでしょう。

valueは整数値で0、1、2、…を入力します。

material-ui ドキュメント(Tabs)

コード例

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import { AppBar, Tabs, Tab, Toolbar} from '@material-ui/core';

const NavBar = () => {
    const [value, setValue] = useState(0);
    const handleChange = (event, value) => {
        setValue(value);
    }
    const hashMap = {
        '#/': 0,
        '#/weathers': 1,
        '#/profile': 2,
    };
    useEffect(() => {
        const hash = location.hash;
        setValue(hashMap[hash]);
    });
    return (
        <AppBar position="static">
            <Toolbar>
                <Tabs value={value} onChange={handleChange}>
                    <Tab icon={<HomeIcon />} label="HOME" component={Link} to="/" />
                    <Tab icon={<BarChartIcon />} label="HOME" component={Link} to="/weathers" />
                    <Tab icon={<PersonIcon />} label="HOME" component={Link} to="/profile" />
                </Tabs>
            </Toolbar>
        </AppBar>
    );
}

このように書くと、NavBarコンポーネントがマウントされたときにuseEffect()が実行されて、URLのハッシュ値を拾いvalueが変更されます。そのため、Tabsのselectedも変更されました。