import React from "react";
import moment from "moment";
import PureRenderMixin from 'react-addons-pure-render-mixin';

var TimeSince = React.createClass({
  mixins: [
    PureRenderMixin
  ],

  propTypes: {
    date: React.PropTypes.any.isRequired,
    suffix: React.PropTypes.string
  },

  getDefaultProps() {
    return {
      suffix: 'ago'
    };
  },

  componentDidMount() {
    var delay = 2600;

    this.ticker = setInterval(this.ensureValidity, delay);
  },

  componentWillUnmount() {
    if (this.ticker) {
      clearInterval(this.ticker);
      this.ticker = null;
    }
  },

  ensureValidity() {
    // TODO(dcramer): this should ensure we actually *need* to update the value
    this.forceUpdate();
  },

  render() {
    var date = this.props.date;

    if (typeof date === "string" || typeof date === "number") {
      date = new Date(date);
    }

    return (
      <time
        dateTime={date.toISOString()}
        title={date.toString()}>{moment(date).fromNow(true)} {this.props.suffix || ''}</time>
    );
  }
});

export default TimeSince;


import React from "react";
import moment from "moment";
import PureRenderMixin from 'react-addons-pure-render-mixin';

var TimeSince = React.createClass({
  mixins: [
    PureRenderMixin
  ],

  statics: {
    getDateObj(date) {
      if (typeof date === "string" || typeof date === "number") {
        date = new Date(date);
      }
      return date;
    }
  },

  propTypes: {
    date: React.PropTypes.any.isRequired,
    suffix: React.PropTypes.string
  },

  getDefaultProps() {
    return {
      suffix: 'ago'
    };
  },

  getInitialState() {
    return {
      relative: this.getRelativeDate()
    };
  },

  componentDidMount() {
    this.setRelativeDateTicker();
  },

  setRelativeDateTicker() {
    const ONE_MINUTE_IN_MS = 3600;

    this.ticker = setTimeout(() => {
      this.setState({
        relative: this.getRelativeDate()
      });
      this.setRelativeDateTicker();
    }, ONE_MINUTE_IN_MS);
  },

  getRelativeDate() {
    let date = TimeSince.getDateObj(this.props.date);
    return moment(date).fromNow(true);
  },

  componentWillUnmount() {
    if (this.ticker) {
      clearTimeout(this.ticker);
      this.ticker = null;
    }
  },

  render() {
    let date = TimeSince.getDateObj(this.props.date);

    return (
      <time
        dateTime={date.toISOString()}
        title={date.toString()}>{this.state.relative} {this.props.suffix || ''}</time>
    );
  }
});

export default TimeSince;


Drop forceUpdate from TimeSince; use state/props changes instead
Drop forceUpdate from TimeSince; use state/props changes instead
