Как вы устанавливаете заголовок документа в React?

115

Я хотел бы установить заголовок документа (в строке заголовка браузера) для моего приложения React. Я пробовал использовать response-document-title (кажется, устаревший) и настройку document.titleв constructorи componentDidMount()- ни одно из этих решений не работает.

Эли
источник
устаревший? @DanAbramov Я думаю, что response-document-title также хорошо работает с React16.
JS dev
Подтверждаю, response-document-title отлично работает с
react

Ответы:

92

Вы можете использовать React Helmet :

import React from 'react'
import { Helmet } from 'react-helmet'

const TITLE = 'My Page Title'

class MyComponent extends React.PureComponent {
  render () {
    return (
      <>
        <Helmet>
          <title>{ TITLE }</title>
        </Helmet>
        ...
      </>
    )
  }
}
цитаты
источник
1
это будет "мигать" содержимое index.html в первую секунду, верно?
nxmohamad
3
Это определенно должен быть главный ответ. Это отличный декларативный способ управления заголовком и другими мета-атрибутами
Ryall
120
import React from 'react'
import ReactDOM from 'react-dom'


class Doc extends React.Component{
  componentDidMount(){
    document.title = "dfsdfsdfsd"
  }

  render(){
    return(
      <b> test </b>
    )
  }
}

ReactDOM.render(
  <Doc />,
  document.getElementById('container')
);

У меня это работает.

Изменить: если вы используете webpack-dev-server, для которого установлено значение true

AlexVestin
источник
5
Это работает, но заголовок документа по-прежнему «React App», пока страница загружается - есть идеи, как это исправить?
eli
7
Измените содержимое тега title в вашем index.html
AlexVestin 09
4
Лучше сделать это декларативно, как в ответе @ quotesBro
Ryall
1
Это нормально для SEO?
Davidm176
@AlexVestin Не очень хорошая идея, если вам нужны разные заголовки для разных представлений в вашем приложении React,
Кевин
55

Для React 16.8 это можно сделать с помощью функционального компонента с помощью useEffect. .

Например:

useEffect(() => {
   document.title = "new title"
}, []);

Второй аргумент в виде массива вызывает useEffect только один раз, что делает его похожим на componentDidMount.

Джордан Дэниэлс
источник
Как это можно проверить с помощью шутки и энзима?
nickstaroba
20

Как уже упоминалось, вы можете использовать document.title = 'My new title'и React Helmet для обновления заголовка страницы. Оба этих решения по-прежнему будут отображать начальный заголовок React App перед загрузкой скриптов.

Если вы используете первоначальное название документа устанавливается в тег файла.create-react-app<title>/public/index.html

Вы можете редактировать это напрямую или использовать заполнитель, который будет заполнен из переменных окружения:

/.env:

REACT_APP_SITE_TITLE='My Title!'
SOME_OTHER_VARS=...

Если по какой-то причине я хотел другое название в моей среде разработки -

/.env.development:

REACT_APP_SITE_TITLE='**DEVELOPMENT** My TITLE! **DEVELOPMENT**'
SOME_OTHER_VARS=...

/public/index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
         ...
         <title>%REACT_APP_SITE_TITLE%</title>
         ...
     </head>
     <body>
         ...
     </body>
</html>

Этот подход также означает, что я могу прочитать переменную окружения заголовка сайта из моего приложения, используя глобальный process.envобъект, что приятно:

console.log(process.env.REACT_APP_SITE_TITLE_URL);
// My Title!

См .: Добавление пользовательских переменных среды.

Грубый
источник
Убедитесь, что файлы .env находятся на том же уровне, что и файл package.json. :)
Ян Смит
10

вы должны установить заголовок документа в жизненном цикле componentWillMount:

componentWillMount() {
    document.title = 'your title name'
  },
Элвин
источник
10
componentWillMount () устарел в последней версии
React
3
В этом случае, как и в большинстве случаев, когда вам нужно удалить устаревший componentWillMount, переместите свой код в componentDidMount
DevTheJo
10

Порталы React позволяют выполнять рендеринг элементов за пределами корневого узла React (например, в <title>), как если бы они были настоящими узлами React. Итак, теперь вы можете установить заголовок чисто и без каких-либо дополнительных зависимостей:

Вот пример:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class Title extends Component {
    constructor(props) {
        super(props);
        this.titleEl = document.getElementsByTagName("title")[0];
    }

    render() {
        let fullTitle;
        if(this.props.pageTitle) {
            fullTitle = this.props.pageTitle + " - " + this.props.siteTitle;
        } else {
            fullTitle = this.props.siteTitle;
        }

        return ReactDOM.createPortal(
            fullTitle || "",
            this.titleEl
        );
    }
}
Title.defaultProps = {
    pageTitle: null,
    siteTitle: "Your Site Name Here",
};

export default Title;

Просто поместите компонент на страницу и установите pageTitle:

<Title pageTitle="Dashboard" />
<Title pageTitle={item.name} />
Полковник тридцать два
источник
Вау, выглядит так многообещающе, React Helmet и document.title работают, но это
круто
Мне понравилось это решение, пока я не понял, что оно просто добавляется fullTitleк содержимому, уже найденному в index.html <title>Default Title</title>.
JWess
Просто удалите заголовок по умолчанию в вашем модуле (не в constructor!) `` Import React from 'react'; импортировать PropTypes из 'prop-types'; импортировать ReactDOM из react-dom; const titleNode = document.getElementsByTagName ("название") [0]; titleNode.innerText = ''; экспорт класса по умолчанию Title расширяет React.PureComponent {static propTypes = {children: PropTypes.node,}; конструктор (реквизит) {супер (реквизит); this.el = titleNode; } render () {вернуть ReactDOM.createPortal (this.props.children, this.el,); }} ``
Анатолий Литинский
9

В React 16.13 вы можете установить его прямо внутри функции рендеринга:

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
    render() {
        document.title = 'wow'
        return <p>Hello</p>
    }
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
)

Для функционального компонента:

function App() {
    document.title = 'wow'
    return <p>Hello</p>
}
М Имам Пратама
источник
2
Это типичная ошибка, которая появляется во многих базах кода реакции: НЕ ДЕЛАЙТЕ ЭТО! Все методы рендеринга должны быть чистыми функциями (без побочных эффектов), если вам нужно выполнить побочный эффект: useEffect для функциональных компонентов или события компонентов в классах (дополнительная информация: reddit.com/r/reactjs/comments/8avfej/… )
Элиас Платек,
6

Просто вы можете создать функцию в файле js и экспортировать ее для использования в компонентах

как показано ниже:

export default function setTitle(title) {
  if (typeof title !== "string") {
     throw new Error("Title should be an string");
  }
  document.title = title;
}

и использовать его в любом компоненте вроде этого:

import React, { Component } from 'react';
import setTitle from './setTitle.js' // no need to js extension at the end

class App extends Component {
  componentDidMount() {
    setTitle("i am a new title");
  }

  render() {
    return (
      <div>
        see the title
      </div>
    );
  }
}

export default App
amin msh
источник
3

Вы можете использовать следующее ниже с document.title = 'Home Page'

import React from 'react'
import { Component } from 'react-dom'


class App extends Component{
  componentDidMount(){
    document.title = "Home Page"
  }

  render(){
    return(
      <p> Title is now equal to Home Page </p>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

или вы можете использовать этот пакет npm npm i react-document-title

import React from 'react'
import { Component } from 'react-dom'
import DocumentTitle from 'react-document-title';


class App extends Component{


  render(){
    return(
      <DocumentTitle title='Home'>
        <h1>Home, sweet home.</h1>
      </DocumentTitle>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

Удачного кодирования !!!

Эстерлинг Аксим Ютубер
источник
2

Я не проверял это слишком тщательно, но, похоже, это работает. Написано на TypeScript.

interface Props {
    children: string|number|Array<string|number>,
}

export default class DocumentTitle extends React.Component<Props> {

    private oldTitle: string = document.title;

    componentWillUnmount(): void {
        document.title = this.oldTitle;
    }

    render() {
        document.title = Array.isArray(this.props.children) ? this.props.children.join('') : this.props.children;
        return null;
    }
}

Применение:

export default class App extends React.Component<Props, State> {

    render() {
        return <>
            <DocumentTitle>{this.state.files.length} Gallery</DocumentTitle>
            <Container>
                Lorem ipsum
            </Container>
        </>
    }
}

Не уверен, почему другие стремятся поместить все свое приложение в свои<Title> компонент, мне это кажется странным.

Обновляя document.titleвнутреннюю часть, render()он будет обновлять / оставаться в актуальном состоянии, если вам нужен динамический заголовок. Он также должен вернуть заголовок при размонтировании. Порталы симпатичны, но кажутся ненужными; здесь нам действительно не нужно манипулировать какими-либо узлами DOM.

mpen
источник
2

Вы можете использовать ReactDOM и изменить <title>тег

ReactDOM.render(
   "New Title",
   document.getElementsByTagName("title")[0]
);
Реза Моради
источник
2

Поскольку React 16.8. для этого вы можете создать собственный хук (аналогично решению @Shortchange):

export function useTitle(title) {
  useEffect(() => {
    const prevTitle = document.title
    document.title = title
    return () => {
      document.title = prevTitle
    }
  })
}

это можно использовать в любом реакционном компоненте, например:

const MyComponent = () => {
  useTitle("New Title")
  return (
    <div>
     ...
    </div>
  )
}

Он обновит заголовок, как только компонент монтируется, и вернет его к предыдущему заголовку при размонтировании.

Мастер Брюс
источник
0

Я использую этот метод, о котором узнал, так как он мне проще. Я использую его в сочетании с функциональной составляющей. Делайте это только в том случае, если вам все равно, что он не будет отображать заголовок, если пользователь отключит Javascript на вашей странице.

Вам нужно сделать две вещи.

1. Зайдите в свой index.html и удалите эту строку здесь

<title>React App</title>

2.Перейдите в свою функцию mainapp и верните это, что представляет собой обычную структуру html, вы можете скопировать и вставить свой основной контент со своего веб-сайта между тегами body:

return (
        <html>
          <head>
            <title>hi</title>
          </head>
          <body></body>
        </html>
      );

Вы можете заменить название как хотите.

Макусиум
источник
0
const setTitle = (title) => {
  const prevTitle = document.title;
  document.title = title;
  return () => document.title = prevTitle;
}

const MyComponent = () => {
  useEffect(() => setTitle('Title while MyComponent is mounted'), []);

  return <div>My Component</div>;
}

Это довольно простое решение, которое я придумал сегодня во время работы. setTitleвозвращает функцию, которая сбрасывает заголовок до того, что было до использования setTitle, она прекрасно работает внутри useEffectловушки React .

Обмен
источник
1
Это правильный способ сделать это. Но было бы неплохо, если бы не пришлось. Концепция достаточно многоразовая, чтобы быть просто на npm.
Евгений Кузьменко
-8

Если вы новичок, вы можете просто спастись от всего этого, зайдя в общую папку вашей папки проекта React, отредактировав заголовок в "index.html" и поместив свой. Не забудьте сохранить, чтобы он отразился.

Stanleynd
источник