Nested document title management for React.
Using npm:
$ npm install react-title-component
Then with a module bundler like webpack that supports either CommonJS or ES2015 modules, use as you would anything else:
// using an ES6 transpiler, like babelimportTitle,{flushTitle}from'react-title-component'// not using an ES6 transpilervarReactTitle=require('react-title-component')varTitle=ReactTitle.defaultvarflushTitle=ReactTitle.flushTitleThe UMD build is also available on npmcdn:
<scriptsrc="https://npmcdn.com/react-title-component/umd/ReactTitleComponent.min.js"></script>You can find the library on window.ReactTitle.
<Titlerender="My Title"/>// `document.title` will now be "My Title"That's nice, but the idea is that you don't want just one component participating in the title of the document. As nested components come in and out of the UI, you often want to append (or prepend) to the current title.
// First instance of `Title`<Titlerender="My Title"/>// Lower in the view hierarchy, another `Title` is rendered.// If you pass it a function you'll get the previous title's value,// so you can append, prepend, or ignore it.<Titlerender={previousTitle=>`${previousTitle} - More Title`}/>// the title, if both of those are rendered, will be:// "My Title - More Title"It ends up looking something like this:
importReactfrom'react'import{render}from'react-dom'importTitlefrom'react-title-component'constApp=React.createClass({render(){return(<div><Titlerender="Awesome Website"/><DeeperPage/>{/* ... */}</div>)}})constDeeperPage=React.createClass({getInitialState(){return{profile: null}},componentDidMount(){fetchProfile(profile=>this.setState({ profile }))},render(){// because it's a component, it gets to participate in the render// lifecycle, updating the title as state changes...const{ profile }=this.stateconsttitle=profile ? 'Loading...' : profile.fullNamereturn(<div><Titlerender={parentTitle=>`More Stuff | ${title}`}/>{/* ... */}</div>)}})If you're using React Router, you probably want all of your route components to add something to the title.
import{flushTitle}from'react-title-component'import{renderToString}from'react-dom/server'constmarkup=renderToString(<App/>)// App has some Titles in it.consttitle=flushTitle()// returns the title and gets ready for the// next requestrenderFullPageHoweverYouDoIt(markup,title)There is one caveat: You can't be removing titles from the middle of the
chain. In other words, make sure that if your component renders a
Title, it always renders a Title.
// GOODrender(){return(<div><Titlerender={prev=>`${prev} | stuff`}/></div>)}// BADrender(){return(<div>{!this.state.screwUpTheTitleLib&&(<Titlerender={prev=>`${prev} | stuff`}/>)}</div>)}This could cause a title in the middle of the "title chain" to be removed and then screw everything else up, the code makes assumptions based on the order they get rendered.
This could be worked around, but it seems like a strange use-case that would complicate the code a bit.
Enjoy!