web-dev-qa-db-fra.com

Est-il possible de modifier le titre de la page avec React-Router v4 +?

Je cherche un moyen de modifier le titre de la page lorsque React-Router v4 + change d'emplacement. J'écoutais une action de changement d'emplacement dans Redux et vérifiais cette route par rapport à un objet metaData.

Lors de l'utilisation de React-Router v4 +, il n'y a pas de liste d'itinéraires fixes. En fait, divers composants autour du site pourraient utiliser Route avec la même chaîne de chemin. Cela signifie que l'ancienne méthode que j'ai utilisée ne fonctionnera plus.

Est-il possible de mettre à jour le titre de la page en appelant des actions lorsque certains itinéraires principaux sont modifiés ou existe-t-il une meilleure méthode pour mettre à jour les métadonnées du site?

18
Sawtaytoes

Dans votre méthode componentDidMount(), faites ceci pour chaque page.

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

Cela changera le titre de votre page, faites ce qui est mentionné ci-dessus pour chaque itinéraire.

Aussi, si c'est plus que juste la partie titre, vérifiez react-helmet C'est une bibliothèque très soignée pour cela, et gère également certains cas Nice Edge.

20
Adeel Imran

<Route /> Les composants ont la propriété render . Vous pouvez donc modifier le titre de la page lorsque l'emplacement change en déclarant vos itinéraires comme suit:

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

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

Dans le composant Page, vous pouvez définir le titre de la route:

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

Mise à jour du 1er août 2019 . Cela fonctionne uniquement avec react-router> = 4.x. Merci à @ supremebeing7

26
phen0menon

En utilisant un composant fonctionnel sur votre page de routage principale, vous pouvez modifier le titre de chaque itinéraire avec seEffect .

Par exemple,

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

Voici ma solution qui est presque la même chose que mettre simplement document.title mais en utilisant 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]
  );
}

Cela présente l'avantage de ne rendre que le rendu si votre modification deps fournie. Ne jamais rediffuser:

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

Render uniquement si mon userId change:

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 ici mais ne peut pas mettre à jour le titre du cadre

Si vous inspectez le <head> du cadre, vous pouvez voir le changement: screenshot

2
TecHunter

Avec un peu d'aide de Helmet:

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

Reprenant l'excellente réponse de phen0menon, pourquoi ne pas prolonger Route au lieu de React.Component?

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 };

cela supprimera le code de frais généraux comme indiqué ci-dessous:

// 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

J'ai construit un peu sur la solution de Thierry Prosts et je me suis retrouvé avec ce qui suit:

// 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;

Et mon implémentation de routeur ressemblait à ceci:

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

Configuration de la route privée:

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

Cela m'a permis de mettre à jour les deux zones publiques avec un nouveau titre et de mettre à jour les zones privées.

1
Hsjakobsen