Giter VIP home page Giter VIP logo

react-document-title's Introduction

React Document Title

Provides a declarative way to specify document.title in a single-page app.
This component can be used on server side as well.

Built with React Side Effect.

Installation

npm install --save react-document-title

Dependencies: React >= 0.13.0

Features

  • Does not emit DOM, not even a <noscript>;
  • Like a normal React compoment, can use its parent's props and state;
  • 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 just as well with isomorphic apps.

Example

Assuming you use something like react-router:

function App() {
  // Use "My Web App" if no child overrides this
  return (
    <DocumentTitle title='My Web App'>
      <SomeRouter />
    </DocumentTitle>
  );
}

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

class NewArticlePage extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: 'Untitled' };
  }

  render() {
    // Update using value from state while this component is mounted
    return (
      <DocumentTitle title={this.state.title}>
        <div>
          <h1>New Article</h1>
          <input
            value={this.state.title}
            onChange={(e) => this.setState({ title: e.target.value })}
          />
        </div>
      </DocumentTitle>
    );
  }
}

Server Usage

If you use it on server, call DocumentTitle.rewind() after rendering components to string to retrieve the title given to the innermost DocumentTitle. You can then embed this title into HTML page template.

Because this component keeps track of mounted instances, you have to make sure to call rewind on server, or you'll get a memory leak.

But What About Meta Tags?

Looking for something more powerful? Check out React Helmet!

react-document-title's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-document-title's Issues

set default title

Hello. Do you think it would be interesting to insert a form of default title for the application, and other pages where I set the DocumentTitle he "add" my title that set along with what I'm setting on the page?

Should use the deepest truthy value

Set the title to the deepest truthy value instead of blindly using the last value. This is helpful when a dynamic value returns null because I'd expect it to use the default value OR the next value up in the tree. I'll create a PR for this.

Feature idea: separator, append & prepend props

Since you have a stack of mounted DocumentTitle instances, it should be possible to do something like:

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

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

Will have a crack at a pull request if I get some time.

Blocks context propagation

The behavior is caused by react-side-effect here (shouldComponentUpdate only does a shallow compare on props, see facebook/react#2517), but the upshot is that using <DocumentTitle/> stops context propagation for a context type declared in its parent but consumed by a descendent.

Totally untested-illustrative-example:

const Parent = React.createClass({
  childContextTypes: {
    foo: React.PropTypes.any
  },
  getChildContext() {
    return { foo: this.state.foo };
  },
  getInitialState() {
    return { foo: null };
  },
  componentDidMount() {
    setTimeout(() => this.setState({foo: 'bar'});
  },
  render() {
    return <DocumentTitle title="sup"><Child/></DocumentTitle/>
  }
});

const Child = React.createClass({
  contextTypes: {
    foo: React.PropTypes.string
  },
  render() {
    // never gets re-rendered with updated `foo` context value
    return <div>{this.context.foo}</div>;
  }
});

I realize that facebook/react#2517 has been discussed to death / is documented clearly in the React Context documentation, but I didn't expect to encounter it in react-document-title (I did not find it in the README).

Update peer dependencies pls.

I just runned into "Two Reacts Won’t Be Friends" issue just by removing import React from 'react' from component using react-document-title.

Btw, isn't better to remove peerDependencies at all?

Upgrade to ESM

Hey @gaearon!!! πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹πŸ‘‹

Would love to see this as an ESM lib with a CJS fallback. Is there any plans for this, or would you accept a PR from someone who will do the work for you! <3 Sean + webpack team.

TypeError: Cannot read property 'string' of undefined at eval

TypeError: Cannot read property 'string' of undefined
at eval (file:///C:/Users/xxxx/Desktop/xxxx/node_modules/react-document-title/index.js:24:28)

Please find my below dependencies and dev dependencies
"dependencies": { "bootstrap": "^3.3.7", "css-loader": "^0.23.1", "extract-text-webpack-plugin": "2.1.2", "file-loader": "^0.9.0", "fixed-data-table": "^0.6.3", "flux": "^2.1.1", "font-awesome": "^4.7.0", "gel-bootstrap-3": "^0.6.23", "google-maps-react": "^1.0.19", "invariant": "^2.2.1", "less": "^2.7.1", "less-loader": "^2.2.3", "loader-utils": "^1.1.0", "lodash": "^4.16.6", "moment": "^2.14.1", "moment-timezone": "^0.5.6", "promise": "^7.1.1", "prop-types": "^15.5.8", "react": "^16.0.0", "react-bootstrap": "^0.31.0", "react-document-title": "^2.0.2", "react-dom": "^16.0.0", "react-esri-map": "0.1.19", "react-flexbox": "^3.1.1", "react-hotkeys": "^0.10.0", "react-infinite-scroller": "^1.0.4", "react-overlays": "^0.6.10", "react-router": "^4.1.1", "react-router-bootstrap": "^0.23.1", "react-router-transition": "0.0.5", "react-scroll": "^1.5.4", "style-loader": "^0.13.1", "url-loader": "^0.5.7", "whatwg-fetch": "^0.11.0" }, "devDependencies": { "babel": "^6.5.2", "babel-core": "^6.10.4", "babel-loader": "^6.2.4", "babel-preset-es2015": "^6.9.0", "babel-preset-react": "^6.11.1", "babel-preset-stage-2": "^6.11.0", "babel-register": "^6.14.0", "better-npm-run": "0.0.8", "chai": "^3.5.0", "chai-enzyme": "^1.0.0-beta.0", "cheerio": "^1.0.0-rc.2", "copy-webpack-plugin": "^2.1.1", "enzyme": "^3.1.1", "enzyme-adapter-react-16": "^1.0.4", "eslint": "^3.19.0", "eslint-plugin-react": "^5.2.2", "eventsource-polyfill": "^0.9.6", "globule": "^1.0.0", "h2o2": "^5.4.0", "hapi": "^13.3.0", "hapi-webpack-plugin": "^1.3.0", "html-webpack-plugin": "^2.29.0", "inert": "^4.1.0", "isomorphic-fetch": "^2.2.1", "json-loader": "^0.5.4", "mocha": "^2.5.3", "mocha-junit-reporter": "^1.11.1", "nodemon": "^1.11.0", "nyc": "^7.1.0", "react-addons-perf": "^15.4.2", "react-addons-test-utils": "^15.4.2", "react-hot-api": "^0.4.5", "react-hot-loader": "^1.3.0", "webpack": "^2.6.1", "webpack-dev-server": "^2.4.5", "webpack-hot-middleware": "^2.6.0" } }

As high order component

Initial idea:

@title(props => `${props.user.name}'s page`)
class SomeComponent extends Component {
}

Has its downsides. One obvious example:

// works
class SomeComponent extends Component {
  render() {
    return (
      <DocumentTitle title={`{this.state.user}'s profile`}>
        ..
      </DocumentTitle>
    );
  }
}

// won't work in the proposed api
@title(...)
class SomeComponent extends Component {
  render() {
    return (
      ..
    );
  }
}

But this doesn't happen very happen often, and I don't think it should. See Smart and Dumb Components.

Would send a PR if this is okay.


Awesome work by the way, @gaearon!

emitting '<noscript></noscript>' to DOM

React = require('react'),
DocumentTitle = require('react-document-title');
var Component = React.createClass({
      render: function () {
        return React.createElement(DocumentTitle, {title: 'irrelevant'} );
      }
});

var markup = React.renderToStaticMarkup(React.createElement(Component));

this is a slightly modified logic of https://github.com/gaearon/react-document-title/blob/master/test/common.js#L9.

it is emitting '' as its markup.

I assume it is a bug since we are claiming in README.md that it doesn't emit anything to DOM

DocumentTitle is undefined when running tests

When using this library with TypeScript, I am encountering errors when running tests:

import DocumentTitle from 'react-document-title';

// ...

renderToString(
                    <DocumentTitle title="Hello World">
                        <AppComponen/>
                    </DocumentTitle>
);

My typings file:

// @types/react-document-title.d.ts

declare module 'react-document-title' {
    import * as React from 'react';

    interface DocumentTitleProps {
        title: string;
    }

    export default class DocumentTitle extends React.Component<DocumentTitleProps, any> {
        public static rewind(): string;
        public static peek(): string;
    }
}

This code runs perfectly fine when executed on the server, but during testing it fails:

Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Debugging shows that the import of react-document-title simply returns undefined when using jest, but the proper class when running the server.

Does anybody know what might be the cause of this?

Node compatibility

According to React's component reference, componentWillMount will also be run on the server. This means bad things will happen (namely, it will attempt to access document on the server, which likely throws an exception).

I don't see any reason not to use componentDidMount instead.

EDIT: See PR #2 for why we can't use componentDidMount for this component.

Lagging title update

I am using react-document-title together with react-router and there is a considerable delay between transitioning to the new URL and the title of the page being updated. Is this a known issue and is there any workaround for it?

Thanks

Issues with importing when using TypeScript

Using TypeScript and @types/react-document-title.

I'm trying to do import * as DocumentTitle from 'react-document-title'; but in my render() I get
[ts] JSX element type 'DocumentTitle' does not have any construct or call signatures.

I tried import DocumentTitle from 'react-document-title'; and the page won't load properly.

export class Test extends React.Component<{}, {}> {
  render() {
    return (
      <DocumentTitle title="Hey">
        Test
      </DocumentTitle>
    );
  }
}

Titles in history

Hello!
I have a suggestion: what about using history.replaceState to store correct page title in browser's history? Because now you can only view correct page title in browser's tab header, but in browser's history you will obtain the value that came within your HTML file.

Readme file Reservations

I'm a bit confused by Readme of this library.

Can be defined in many places throughout the application

I'm surprised because though the document title can change many times, at any given time there is only one title. Isn't using DocumentTitle component in various places throught the application, splitting the logic of the aplication?

mistake

discovered that I posted this issue in error. closing.

Support export.default?

Hi. I use TypeScript with React. One thing is that I'm not able to import DocumentTitle with DT d.ts. This is not a big deal, s I've created my own d.ts for DocumentTitle. Another thing is that your module misses default, so I have to use ugly import DocumentTitle = require('react-document-title'). Thanks

Suffix support?

Hi, it would be nice if there was a global suffix support.

This is how I imagine it could work API-wise:

Root level, producing MyApp.

<DocumentTitle title="null" suffix="MyApp" separator=" | ">
 ...
</DocumentTitle>

Inside a specific page, producing Index | MyApp.

<DocumentTitle title="null" suffix="MyApp" separator=" | ">
   <DocumentTitle title="Index">...<DocumentTitle>
</DocumentTitle>

There could be also custom format function for those who need more power:

<DocumentTitle title="null" format={(value) => value ? value+' | MyApp' : 'MyApp'}>
   ...
</DocumentTitle>

Use of React.Children.only()

Is the use of React.Children.only() necessary? It enforces more mark-up.

<DocumentTitle title="...">
  <div>
    <div>...</div>
    <div>...</div>
  </div>
</DocumentTitle>

Instead of just:

<DocumentTitle title="...">
  <div>...</div>
  <div>...</div>
</DocumentTitle>

Containers are no longer required in React v16, so it would be nice to avoid having them here, too.

Title parts

Thank you for this component! I looked at the source and it's much simpler than I thought. It doesn't seem to allow to have title "parts" as in the following example:

A top level "app" component with:

<DocumentTitle title="My App">
  <RouteHandler/>
</DocumentTitle>

Then, inside the route handler component, a nested title:

<DocumentTitle title="Login">
  <h2>Login</h2>
  <form>...</form>
</DocumentTitle>

In this very simple case, when I am on the /login route the document.title will be set to "Login". Would there be a way to configure the side effect to set the title to, e.g. "My App :: Login"?

Not work in iphone wechat

It can not work properly in iphone wechat.

Below is my code.

// routes.jsx
export default (
  <Route>
    <Route path="/" component={ App }>
      <Route path="dailyoperation" component={ DailyOperation } />
    </Route>
    <Route path="/test1" component={ Test1 }/>
    <Route path="/test2" component={ Test2 }/>
    <Route path="/test3" component={ Test3 }/>
  </Route>
);
// Test2.jsx

import React, { Component, PropTypes } from 'react';
import DocumentTitle from 'react-document-title';
import { Link } from 'react-router';

class Test2 extends Component {
  render() {
    return (
      <DocumentTitle title="test2">
      <div>
        test2 <Link to="/test3">test3</Link>
      </div>
      </DocumentTitle>
    );
  }
}

export default Test2;

I test in In iphone5,6 wechat browser, the title does't change when i switch in different page.

Leads to memory leaks when it's used with renderToString

My react app is server-side rendered. I used NodeJS process.memoryUsage() function for a profiling a rendering process and noticed that after calling renderToString memory never released.

After removing this string: <DocumentTitle title={title} /> GC is able to utilize a memory.

Expand support and rename project

I've been using react-document-title for an isomorphic project and quickly discovered that most of the pages that are being rendered on the server could use generated metadata such as description and Open Graph.

I'm proposing renaming the project to react-document-metadata and expand usage to arbitrary props in addition to title:

<Metadata
  title="My fine page"
  opengraph={{image: this.state.image.url}}
  description={this.getDescription()} />

Naturally only title would be read by the browser for updating window.title but it could also be expanded to support things like dynamic favicons.

Thoughts?

Keep seeing warnings about missing 'key' prop for DocumentTitle

Not sure if I'm doing something wrong, if this is a problem with this component, or if the issue is in react-side-effect, but it's a slightly distracting (if harmless) warning that I can't get rid of:

bundle.0ae94dcb667ef563f4ee.js:sourcemap:3890 Warning: Each child in an array or iterator should have a unique "key" prop. See https://fb.me/react-warning-keys for more information.
    in div
    in DocumentTitle (created by SideEffect(DocumentTitle))
    in SideEffect(DocumentTitle)
    in NavbarView (created by RouterContext)
    in RouterContext (created by Router)
    in Router
    in Provider

How to get started?

Sorry for the newbie question, but I'm having trouble getting this running.

I've run npm install --save react-document-title

Then I tried
require('../../node_modules/react-document-title/index.js') from my main.js file, then use webpack or browserify to create a bundle.js and link that in instead of the main.js file, but it says Uncaught ReferenceError: DocumentTitle is not defined in my JSX file.

I see that the bundle is loaded in the browser, and I can see the react-document-title code in the bundle, but it's not available to my JSX for some reason. It's probably a rookie mistake, but I'm stumped. Hope you can give any pointers.

Cheers

Example source code:

index.html

    <script src="https://fb.me/react-with-addons-0.13.3.js"></script>
    <script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/0.13.3/ReactRouter.min.js"></script>
    <script src="~/src/js/bundle.js"></script>
    <script type="text/jsx" src="~/Content/lib/jsx/main.jsx"></script>

main.js

'use strict'

var DocumentTitle = require('../../node_modules/react-document-title/index.js');

main.jsx

var Router = ReactRouter;
var DefaultRoute = Router.DefaultRoute;
var Link = Router.Link;
var Route = Router.Route;
var RouteHandler = Router.RouteHandler;

var App = React.createClass({
    render: function() {
        return (
            <DocumentTitle title='Home'>
                <this.props.activeRouteHandler />
                <div id="wrapper">
                </div>
            </DocumentTitle>
        );
    }
});

Race conditions

Since 'mountedInstances' is a static property on DocumentTitle it's shared state across all requests.
Doesn't this cause race conditions? I'm not sure I totally get how it works yet (i'm new to nodejs and react too).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.