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?
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.
<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
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>
);
}
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:
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>
)
}
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" />
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.