29

React には を管理する組み込みの方法がないため、以前はルート ハンドラーdocument.title内に設定していました。componentDidMount

stateただし、非同期で取得したものに基づいてタイトルを修正する必要があります。に割り当てを入れ始めましたが、ときどきいくつかのページに割り当てcomponentDidUpdateを入れるのを忘れてしまい、document.title気が付くまで以前のタイトルが残ります。

理想的にはdocument.title、代入することなく、宣言的に表現する方法が欲しいです。いくつかのネスト レベルでドキュメント タイトルを指定できるようにしたい場合は、ある種の「偽の」コンポーネントがおそらく最も便利です。

  • 最上位 (デフォルトのタイトル)。
  • ページ レベル (すべてではなく一部のページ)。
  • 場合によっては、内部コンポーネント レベルで (ユーザーがフィールドに入力するなど)。

追加要件:

  • 子で指定されたタイトルは、親で指定されたタイトルをオーバーライドする必要があります。
  • 信頼できる (ルート変更時のクリーンアップを保証する);
  • DOM を発行してはなりません (つまり、コンポーネントが を返すハックはありません<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>
    );
  }
});

ソース

マウントされたインスタンスを追跡し、更新、マウント、またはアンマウントされるたびに、マウントされたインスタンス スタックtitleの一番上にあるものだけを使用します。DocumentTitleサーバー上では、が発生しますが、またはcomponentWillMountを取得しないため、文字列を返し、状態を破棄して次のリクエストに備えるを導入します。didMountwillUnmountDocumentTitle.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 に答える
4

実際にはreact - document-title よりも洗練されています。タイトル、説明、およびセクション内のその他のものを変更できます。

于 2015-08-01T22:38:16.247 に答える