如何在React应用程序中更新document.title?

时间:2022-12-12 20:35:41

Since React doesn't have any builtin way to manage document.title, I used to set it inside componentDidMount of my route handlers.

由于React没有任何内置的方法来管理document.title,我曾经在我的路由处理程序的componentDidMount中设置它。

However now I need to amend the title based on state fetched asynchronously. I started putting assingments into componentDidUpdate, but every now and then I forget to put document.title assignment into some pages, and previous title sticks around until I finally notice it.

但是现在我需要根据异步获取的状态修改标题。我开始将assingments放到componentDidUpdate中,但我偶尔忘记将document.title赋值放到某些页面中,之前的标题一直存在,直到我终于注意到它为止。

Ideally I'd like a way to express document.title declaratively, without having to assign it. Some kind of “fake” component would probably be most convenient, given that I want to be able to specify the document title at several nesting levels:

理想情况下,我想要一种以声明方式表达document.title的方法,而不必分配它。鉴于我希望能够在几个嵌套级别指定文档标题,某种“假”组件可能是最方便的:

  • On top level (the default title);
  • 在顶层(默认标题);

  • On page level (for some of the pages, but not all);
  • 在页面级别(对于某些页面,但不是全部);

  • Sometimes, on inner component level (e.g. user typing into a field).
  • 有时,在内部组件级别(例如,用户键入字段)。

Additional requirements:

  • Title specified in child should override title specified by parent;
  • 子项中指定的标题应覆盖父项指定的标题;

  • Reliable (guarantees cleanup on route change);
  • 可靠(保证路线变更时的清理);

  • Should not emit any DOM (i.e. no hacks with component returning <noscript>);
  • 不应该发出任何DOM(即没有组件返回的hacks

  • I'm using react-router but it's better if this component works with other routers too.
  • 我正在使用react-router,但如果这个组件也可以与其他路由器一起工作,那就更好了。

Anything I can use?

我能用什么?

5 个解决方案

#1


51  

I wrote react-document-title just for that.

我为此写了反应文档标题。

It provides a declarative way to specify document.title in a single-page app.
If you want to get title on server after rendering components to string, call DocumentTitle.rewind().

它提供了一种在单页面应用程序中指定document.title的声明方式。如果要在将组件呈现为字符串后在服务器上获取标题,请调用DocumentTitle.rewind()。

Features

  • Does not emit DOM, not even a <noscript>;
  • 不发出DOM,甚至不发出

  • Like a normal React compoment, can use its parent's props and state;
  • 像普通的React组件一样,可以使用其父级的道具和状态;

  • Can be defined in many places throughout the application;
  • 可以在整个应用程序的许多地方定义;

  • Supports arbitrary levels of nesting, so you can define app-wide and page-specific titles;
  • 支持任意级别的嵌套,因此您可以定义应用程序范围和页面特定的标题;

  • Works on client and server.
  • 适用于客户端和服务器。

Example

Assuming you use something like react-router:

假设你使用像react-router这样的东西:

var App = React.createClass({
  render: function () {
    // Use "My Web App" if no child overrides this
    return (
      <DocumentTitle title='My Web App'>
        <this.props.activeRouteHandler />
      </DocumentTitle>
    );
  }
});

var HomePage = React.createClass({
  render: function () {
    // Use "Home" while this component is mounted
    return (
      <DocumentTitle title='Home'>
        <h1>Home, sweet home.</h1>
      </DocumentTitle>
    );
  }
});

var NewArticlePage = React.createClass({
  mixins: [LinkStateMixin],

  render: function () {
    // Update using value from state while this component is mounted
    return (
      <DocumentTitle title={this.state.title || 'Untitled'}>
        <div>
          <h1>New Article</h1>
          <input valueLink={this.linkState('title')} />
        </div>
      </DocumentTitle>
    );
  }
});

Source

I keep track of mounted instances and only use title given to the top DocumentTitle in the mounted instance stack whenever it updates, gets mounted or unmounted. On server, componentWillMount fires but we won't get didMount or willUnmount, so we introduce DocumentTitle.rewind() that returns a string and destroys state to prepare for next request.

我跟踪已安装的实例,并且只有在更新,安装或卸载时才使用已安装的实例堆栈中的*DocumentTitle的标题。在服务器上,componentWillMount会触发,但我们不会获取didMount或willUnmount,因此我们引入了DocumentTitle.rewind(),它返回一个字符串并销毁状态以准备下一个请求。

var DocumentTitle = React.createClass({
  propTypes: {
    title: PropTypes.string
  },

  statics: {
    mountedInstances: [],

    rewind: function () {
      var activeInstance = DocumentTitle.getActiveInstance();
      DocumentTitle.mountedInstances.splice(0);

      if (activeInstance) {
        return activeInstance.props.title;
      }
    },

    getActiveInstance: function () {
      var length = DocumentTitle.mountedInstances.length;
      if (length > 0) {
        return DocumentTitle.mountedInstances[length - 1];
      }
    },

    updateDocumentTitle: function () {
      if (typeof document === 'undefined') {
        return;
      }

      var activeInstance = DocumentTitle.getActiveInstance();
      if (activeInstance) {
        document.title = activeInstance.props.title;
      }
    }
  },

  getDefaultProps: function () {
    return {
      title: ''
    };
  },

  isActive: function () {
    return this === DocumentTitle.getActiveInstance();
  },

  componentWillMount: function () {
    DocumentTitle.mountedInstances.push(this);
    DocumentTitle.updateDocumentTitle();
  },

  componentDidUpdate: function (prevProps) {
    if (this.isActive() && prevProps.title !== this.props.title) {
      DocumentTitle.updateDocumentTitle();
    }
  },

  componentWillUnmount: function () {
    var index = DocumentTitle.mountedInstances.indexOf(this);
    DocumentTitle.mountedInstances.splice(index, 1);
    DocumentTitle.updateDocumentTitle();
  },

  render: function () {
    if (this.props.children) {
      return Children.only(this.props.children);
    } else {
      return null;
    }
  }
});

module.exports = DocumentTitle;

#2


20  

Take a look at the NFL's react-helmet.

看看NFL的反应头盔吧。

#3


6  

class Layout extends React.Component {
  constructor(props){
    super(props);
    document.title = this.props.title;
  }
  render(){
    return(
      <div>
      </div>
    );
  }
}

and then <Layout title="My Title"/> that easy!

然后 <布局标题=“我的标题” />这很简单!

#4


4  

Try react-frozenhead, it's actually more sophisticated than react-document-title - it allows us change title, description and anything else in section.

尝试react-frozenhead,它实际上比反应文档标题更复杂 - 它允许我们更改标题,描述和部分中的任何其他内容。

#5


0  

Meanwhile, 3 years have gone! ;-)
If you want to manipulate other page headers than title (like description, canonical, etc.), react-document-meta NPM dependency could be a good thing to use.

与此同时,3年过去了! ;-)如果你想操纵其他页面标题而不是标题(如描述,规范等),react-document-meta NPM依赖可能是一件好事。

#1


51  

I wrote react-document-title just for that.

我为此写了反应文档标题。

It provides a declarative way to specify document.title in a single-page app.
If you want to get title on server after rendering components to string, call DocumentTitle.rewind().

它提供了一种在单页面应用程序中指定document.title的声明方式。如果要在将组件呈现为字符串后在服务器上获取标题,请调用DocumentTitle.rewind()。

Features

  • Does not emit DOM, not even a <noscript>;
  • 不发出DOM,甚至不发出

  • Like a normal React compoment, can use its parent's props and state;
  • 像普通的React组件一样,可以使用其父级的道具和状态;

  • Can be defined in many places throughout the application;
  • 可以在整个应用程序的许多地方定义;

  • Supports arbitrary levels of nesting, so you can define app-wide and page-specific titles;
  • 支持任意级别的嵌套,因此您可以定义应用程序范围和页面特定的标题;

  • Works on client and server.
  • 适用于客户端和服务器。

Example

Assuming you use something like react-router:

假设你使用像react-router这样的东西:

var App = React.createClass({
  render: function () {
    // Use "My Web App" if no child overrides this
    return (
      <DocumentTitle title='My Web App'>
        <this.props.activeRouteHandler />
      </DocumentTitle>
    );
  }
});

var HomePage = React.createClass({
  render: function () {
    // Use "Home" while this component is mounted
    return (
      <DocumentTitle title='Home'>
        <h1>Home, sweet home.</h1>
      </DocumentTitle>
    );
  }
});

var NewArticlePage = React.createClass({
  mixins: [LinkStateMixin],

  render: function () {
    // Update using value from state while this component is mounted
    return (
      <DocumentTitle title={this.state.title || 'Untitled'}>
        <div>
          <h1>New Article</h1>
          <input valueLink={this.linkState('title')} />
        </div>
      </DocumentTitle>
    );
  }
});

Source

I keep track of mounted instances and only use title given to the top DocumentTitle in the mounted instance stack whenever it updates, gets mounted or unmounted. On server, componentWillMount fires but we won't get didMount or willUnmount, so we introduce DocumentTitle.rewind() that returns a string and destroys state to prepare for next request.

我跟踪已安装的实例,并且只有在更新,安装或卸载时才使用已安装的实例堆栈中的*DocumentTitle的标题。在服务器上,componentWillMount会触发,但我们不会获取didMount或willUnmount,因此我们引入了DocumentTitle.rewind(),它返回一个字符串并销毁状态以准备下一个请求。

var DocumentTitle = React.createClass({
  propTypes: {
    title: PropTypes.string
  },

  statics: {
    mountedInstances: [],

    rewind: function () {
      var activeInstance = DocumentTitle.getActiveInstance();
      DocumentTitle.mountedInstances.splice(0);

      if (activeInstance) {
        return activeInstance.props.title;
      }
    },

    getActiveInstance: function () {
      var length = DocumentTitle.mountedInstances.length;
      if (length > 0) {
        return DocumentTitle.mountedInstances[length - 1];
      }
    },

    updateDocumentTitle: function () {
      if (typeof document === 'undefined') {
        return;
      }

      var activeInstance = DocumentTitle.getActiveInstance();
      if (activeInstance) {
        document.title = activeInstance.props.title;
      }
    }
  },

  getDefaultProps: function () {
    return {
      title: ''
    };
  },

  isActive: function () {
    return this === DocumentTitle.getActiveInstance();
  },

  componentWillMount: function () {
    DocumentTitle.mountedInstances.push(this);
    DocumentTitle.updateDocumentTitle();
  },

  componentDidUpdate: function (prevProps) {
    if (this.isActive() && prevProps.title !== this.props.title) {
      DocumentTitle.updateDocumentTitle();
    }
  },

  componentWillUnmount: function () {
    var index = DocumentTitle.mountedInstances.indexOf(this);
    DocumentTitle.mountedInstances.splice(index, 1);
    DocumentTitle.updateDocumentTitle();
  },

  render: function () {
    if (this.props.children) {
      return Children.only(this.props.children);
    } else {
      return null;
    }
  }
});

module.exports = DocumentTitle;

#2


20  

Take a look at the NFL's react-helmet.

看看NFL的反应头盔吧。

#3


6  

class Layout extends React.Component {
  constructor(props){
    super(props);
    document.title = this.props.title;
  }
  render(){
    return(
      <div>
      </div>
    );
  }
}

and then <Layout title="My Title"/> that easy!

然后 <布局标题=“我的标题” />这很简单!

#4


4  

Try react-frozenhead, it's actually more sophisticated than react-document-title - it allows us change title, description and anything else in section.

尝试react-frozenhead,它实际上比反应文档标题更复杂 - 它允许我们更改标题,描述和部分中的任何其他内容。

#5


0  

Meanwhile, 3 years have gone! ;-)
If you want to manipulate other page headers than title (like description, canonical, etc.), react-document-meta NPM dependency could be a good thing to use.

与此同时,3年过去了! ;-)如果你想操纵其他页面标题而不是标题(如描述,规范等),react-document-meta NPM依赖可能是一件好事。