it-roy-ru.com

Есть ли способ изменить заголовок страницы с помощью React-Router v4 +?

Я ищу способ изменить заголовок страницы, когда React-Router v4 + меняет местоположение. Раньше я слушал действие по изменению местоположения в Redux и проверял этот маршрут по объекту metaData.

При использовании React-Router v4 + список фиксированных маршрутов отсутствует. Фактически, различные компоненты сайта могут использовать Route с одинаковой строкой пути. Это означает, что старый метод, который я использовал, больше не будет работать.

Есть ли способ, которым я могу обновить заголовок страницы, вызывая действия при изменении определенных основных маршрутов, или есть лучший способ обновить метаданные сайта?

18
Sawtaytoes

В вашем методе componentDidMount() сделайте это для каждой страницы

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

Это изменит заголовок вашей страницы, сделайте вышеупомянутое для каждого маршрута.

Также, если это больше, чем просто заглавная часть, проверьте реагирующий шлем Это очень удобная библиотека для этого, которая также обрабатывает некоторые случаи 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

Обновление 1 августа 2019 г. . Это работает только с response-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, почему бы не расширить 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" />
1
Thierry Prost

Я немного построил решение 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 }
            }}
          />
        )
      }
    />
  );
}

Это позволило мне обновлять как публичные области с новым названием, так и частные области.

1
Hsjakobsen