29

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

但是现在我需要根据state异步获取来修改标题。我开始将 assingments 放入componentDidUpdate,但时不时忘记将document.titleassignment 放入某些页面,并且以前的标题一直存在,直到我终于注意到它。

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

  • 在顶层(默认标题);
  • 在页面级别(对于某些页面,但不是全部);
  • 有时,在内部组件级别(例如,用户输入字段)。

其他要求:

  • 子项中指定的标题应覆盖父项指定的标题;
  • 可靠(保证路线变更时的清理);
  • 不应该发出任何 DOM(即没有组件返回的 hack <noscript>);
  • 我正在使用 react-router 但是如果这个组件也可以与其他路由器一起使用会更好。

有什么我可以用的吗?

4

5 回答 5

54

我为此写了react-document-title

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

特征

  • 不发出 DOM,甚至不发出<noscript>;
  • 像普通的 React 组件一样,可以使用其父级的propsand state;
  • 可以在整个应用程序的许多地方定义;
  • 支持任意级别的嵌套,因此您可以定义应用范围和页面特定的标题;
  • 适用于客户端和服务器。

例子

假设您使用类似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>
    );
  }
});

来源

我跟踪挂载的实例,并且只在它更新、挂载或卸载时使用titleDocumentTitle挂载实例堆栈的顶部。在服务器上,componentWillMount触发但我们不会得到didMountor 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;
于 2014-10-08T21:23:56.870 回答
21

看看 NFL 的react-helmet

于 2015-12-08T19:56:29.373 回答
7
class Layout extends React.Component {
  constructor(props){
    super(props);
    document.title = this.props.title;
  }
  render(){
    return(
      <div>
      </div>
    );
  }
}

然后就<Layout title="My Title"/>这么简单!

于 2017-02-26T06:15:17.007 回答
4

试试react-frozenhead,它实际上比 react-document-title 更复杂——它允许我们更改标题、描述和部分中的任何其他内容。

于 2015-08-01T22:38:16.247 回答
0

与此同时,3年过去了!;-)
如果您想操作除标题以外的其他页面标题(如描述、规范等),react-document-meta NPM 依赖项可能是一个好用的东西。

于 2018-01-15T16:55:59.990 回答