web-dev-qa-db-ja.com

React-Router v4 +でページタイトルを変更する方法はありますか?

React-Router v4 +が場所を変更したときにページタイトルを変更する方法を探しています。 Reduxで場所の変更アクションをリッスンし、そのルートをmetaDataオブジェクトに対してチェックしていました。

React-Router v4 +を使用する場合、固定ルートリストはありません。実際、サイト内のさまざまなコンポーネントは、同じパス文字列でRouteを使用できます。つまり、私が使用した古い方法はもう機能しません。

特定の主要なルートが変更されたときにアクションを呼び出してページタイトルを更新する方法はありますか、またはサイトのメタデータを更新するより良い方法がありますか?

18
Sawtaytoes

componentDidMount()メソッドで、すべてのページに対してこれを行います

componentDidMount() {
  document.title = 'Your page title here';
}

これにより、ページタイトルが変更されます。すべてのルートについて上記の手順を実行します。

また、タイトル部分だけではない場合は、 react-helmet を確認してください。これは非常にきちんとしたライブラリであり、Nice Edgeのケースも処理します。

20
Adeel Imran

<Route />コンポーネントには render プロパティがあります。そのため、次のようなルートを宣言することで、場所が変わったときにページタイトルを変更できます。

<Route
  exact
  path="/"
  render={props => (
    <Page {...props} component={Index} title="Index Page" />
  )}
/>

<Route
  path="/about"
  render={props => (
    <Page {...props} component={About} title="About Page" />
  )}
/>

Pageコンポーネントでは、ルートタイトルを設定できます。

import React from "react"

/* 
 * Component which serves the purpose of a "root route component". 
 */
class Page extends React.Component {
  /**
   * Here, we define a react lifecycle method that gets executed each time 
   * our component is mounted to the DOM, which is exactly what we want in this case
   */
  componentDidMount() {
    document.title = this.props.title
  }

  /**
   * Here, we use a component prop to render 
   * a component, as specified in route configuration
   */
  render() {
    const PageComponent = this.props.component

    return (
      <PageComponent />
    )
  }
}

export default Page

2019年8月1日更新これは、react-router> = 4.xでのみ機能します。 @ supremebeing7に感謝

26
phen0menon

メインルーティングページの機能コンポーネントを使用して、 seEffect で各ルート変更のタイトルを変更できます。

例えば、

const Routes = () => {
    useEffect(() => {
      let title = history.location.pathname
      document.title = title;
    });

    return (
      <Switch>
        <Route path='/a' />
        <Route path='/b' />
        <Route path='/c' />
      </Switch>
    );
}
3
Jordan Daniels

私の解決策は、単にdocument.titleを設定することとほぼ同じですが、useEffectを使用することです。

/**
* Update the document title with provided string
 * @param titleOrFn can be a String or a function.
 * @param deps? if provided, the title will be updated when one of these values changes
 */
function useTitle(titleOrFn, ...deps) {
  useEffect(
    () => {
      document.title = isFunction(titleOrFn) ? titleOrFn() : titleOrFn;
    },
    [...deps]
  );
}

これには、提供されたdeps変更があった場合にのみ再レンダリングするという利点があります。再レンダリングしない:

const Home = () => {
  useTitle('Home');
  return (
    <div>
      <h1>Home</h1>
      <p>This is the Home Page</p> 
    </div>
  );
}

userIdが変更された場合のみレンダリングします:

const UserProfile = ({ match }) => {
  const userId = match.params.userId;
  useTitle(() => `Profile of ${userId}`, [userId]);
  return (
    <div>
      <h1>User page</h1>
      <p>
        This is the user page of user <span>{userId}</span>
      </p>
    </div>
  );
};

// ... in route definitions
<Route path="/user/:userId" component={UserProfile} />
// ...

CodePenはここにありますが、フレームタイトルを更新できません

フレームの<head>を調べると、変更を確認できます。 screenshot

2
TecHunter

ヘルメットから少し助けを借りて:

import React from 'react'
import Helmet from 'react-helmet'
import { Route, BrowserRouter, Switch } from 'react-router-dom'

function RouteWithTitle({ title, ...props }) {
  return (
    <>
      <Helmet>
        <title>{title}</title>
      </Helmet>
      <Route {...props} />
    </>
  )
}

export default function Routing() {
  return (
    <BrowserRouter>
      <Switch>
        <RouteWithTitle title="Hello world" exact={true} path="/" component={Home} />
      </Switch>
    </BrowserRouter>
  )
}
1
Fellow Stranger

Phen0menonの優れた答えから、React.Componentの代わりにRouteを拡張してみませんか?

import React, { useEffect } from 'react';
import { Route } from 'react-router-dom';
import PropTypes from 'prop-types';

const Page = ({ title, ...rest }) => {
  useEffect(() => {
    document.title = title), []
  };
  return <Route {...rest} />;
};

Page.propTypes = {
  title: PropTypes.string.isRequired,
};

export { Page };

これにより、以下に示すオーバーヘッドコードが削除されます。

// old:
<Route
  exact
  path="/"
  render={props => (
    <Page {...props} component={Index} title="Index Page" />
  )}
/>
// improvement:
<Page 
  exact
  path="/"
  component={Index}
  title="Index Page" />
1
Thierry Prost

ティエリー・プロストのソリューションを少し構築して、次のようになりました。

// Page.jsx
import React from 'react';
import { Route } from 'react-router-dom';

class Page extends Route {
  componentDidMount() {
    document.title = "Website name | " + this.props.title;
  }

  componentDidUpdate() {      
      document.title = "Website name | " + this.props.title;
  }

  render() {
    const { title, ...rest } = this.props;
    return <Route {...rest} />;
  }
}

export default Page;

そして、ルーターの実装は次のようになりました。

// App.js / Index.js
<Router>
    <App>
      <Switch>
         <Page path="/" component={Index} title="Index" />
         <PrivateRoute path="/secure" component={SecurePage} title="Secure" />
      </Switch>
    </App>    
  </Router>

プライベートルートのセットアップ:

// PrivateRoute
function PrivateRoute({ component: Component, ...rest }) {
  return (
    <Page
      {...rest}
      render={props =>
        isAuthenticated ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{
              pathname: "/",
              state: { from: props.location }
            }}
          />
        )
      }
    />
  );
}

これにより、新しいタイトルでパブリックエリアを更新し、プライベートエリアも更新することができました。

1
Hsjakobsen