Есть ли способ изменить заголовок страницы с помощью React-Router v4+?
Я ищу способ изменить заголовок страницы, когда React-Router v4+ изменяет местоположение. Я привык слушать действие изменения местоположения в Redux и проверять этот маршрут на объект metaData
.
При использовании React-Router v4+ нет списка фиксированных маршрутов. Фактически, различные компоненты вокруг сайта могут использовать Route
с той же строкой пути. Это означает, что старый метод, который я использовал, больше не будет работать.
Есть ли способ обновить заголовок страницы, вызывая действия при изменении некоторых основных маршрутов или улучшая лучший способ обновления метаданных сайта?
Ответы
Ответ 1
В вашем методе componentDidMount()
сделайте это для каждой страницы
componentDidMount() {
document.title = 'Your page title here';
}
Это изменит заголовок вашей страницы, сделайте вышеуказанное для каждого маршрута.
Также, если это больше, чем просто заглавная часть, проверьте ответ-шлем. Это очень аккуратная библиотека для этого, которая также обрабатывает некоторые замечательные крайние случаи.
Ответ 2
Компоненты <Route />
имеют свойство рендеринга. Таким образом, вы можете изменить заголовок страницы при изменении местоположения, объявив свои маршруты следующим образом:
<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
Обновление 1 августа 2019 года. Это работает только с response-router> = 4.x. Благодаря @supremebeing7
Ответ 3
Используя функциональный компонент на главной странице маршрутизации, вы можете изменять заголовок при каждом изменении маршрута с помощью useEffect.
Например,
const Routes = () => {
useEffect(() => {
let title = history.location.pathname
document.title = title;
});
return (
<Switch>
<Route path='/a' />
<Route path='/b' />
<Route path='/c' />
</Switch>
);
}
Ответ 4
В ответ на отличный ответ phen0menon, почему бы не расширить Route вместо 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 };
это удалит служебный код, как показано ниже:
// old:
<Route
exact
path="/"
render={props => (
<Page {...props} component={Index} title="Index Page" />
)}
/>
// improvement:
<Page
exact
path="/"
component={Index}
title="Index Page" />
Обновите другой способ сделать это с помощью хуков:
import { useEffect } from 'react';
/** Hook for changing title */
export const useTitle = title => {
useEffect(() => {
title && (document.title = title);
}, []);
};
Ответ 5
Я немного построил решение Thierry Prosts и получил следующее:
// 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;
И моя реализация Router выглядела так:
// 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 }
}}
/>
)
}
/>
);
}
Это позволило мне обновлять как публичные области с новым названием, так и частные области.
Ответ 6
Вот мое решение, которое почти такое же, как useEffect
установка 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>
кадра, вы увидите изменение:
Ответ 7
С небольшой помощью от Шлема:
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>
)
}