Since React doesn't have any builtin way to manage document.title
, I used to set it inside componentDidMount
of my route handlers.
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.
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:
Additional requirements:
<noscript>
);Anything I can use?
As others have mentioned, you can use document. title = 'My new title' and React Helmet to update the page title.
Q . Which Hook could be used to update the document's title? useEffect(function updateTitle() { document.
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()
.
<noscript>
;props
and state
;Assuming you use something like 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> ); } });
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.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With