Skip to content

Commit

Permalink
Fix <FormattedRelative> to update when value changes (formatjs#496)
Browse files Browse the repository at this point in the history
This fixes the issue where `<FormattedRelative>` would render the
incorrect relative time when its `props.value` was updated.

Fixes formatjs#495
  • Loading branch information
ericf authored Jun 14, 2016
1 parent 9cde648 commit 653cee7
Showing 2 changed files with 46 additions and 4 deletions.
27 changes: 23 additions & 4 deletions src/components/relative.js
Original file line number Diff line number Diff line change
@@ -47,6 +47,17 @@ function getUnitDelay(units) {
}
}

function isSameDate(a, b) {
if (a === b) {
return true;
}

let aTime = new Date(a).getTime();
let bTime = new Date(b).getTime();

return isFinite(aTime) && isFinite(bTime) && aTime === bTime;
}

export default class FormattedRelative extends Component {
constructor(props, context) {
super(props, context);
@@ -91,6 +102,18 @@ export default class FormattedRelative extends Component {
}, delay);
}

componentDidMount() {
this.scheduleNextUpdate(this.props, this.state);
}

componentWillReceiveProps({value: nextValue}) {
// When the `props.value` date changes, `state.now` needs to be updated,
// and the next update can be rescheduled.
if (!isSameDate(nextValue, this.props.value)) {
this.setState({now: this.context.intl.now()});
}
}

shouldComponentUpdate(...next) {
return shouldIntlComponentUpdate(this, ...next);
}
@@ -99,10 +122,6 @@ export default class FormattedRelative extends Component {
this.scheduleNextUpdate(nextProps, nextState);
}

componentDidMount() {
this.scheduleNextUpdate(this.props, this.state);
}

componentWillUnmount() {
clearTimeout(this._timer);
}
23 changes: 23 additions & 0 deletions test/unit/components/relative.js
Original file line number Diff line number Diff line change
@@ -210,6 +210,29 @@ describe('<FormattedRelative>', () => {
}, 10);
});

it('updates when the `value` prop changes', () => {
const {intl} = intlProvider.getChildContext();
const now = intl.now();

renderer.render(<FormattedRelative value={now} updateInterval={1} />, {intl});
const renderedOne = renderer.getRenderOutput();

// Shallow Renderer doesn't call `componentDidMount()`. This forces the
// scheduler to schedule an update based on the `updateInterval`.
renderer.getMountedInstance().componentDidMount();

// Update `now()` to act like the <IntlProvider> is mounted.
const nextNow = now + 1000;
intl.now = () => nextNow;

renderer.render(<FormattedRelative value={nextNow} updateInterval={1} />, {intl});
const renderedTwo = renderer.getRenderOutput();

expect(renderedTwo).toEqualJSX(renderedOne);

renderer.unmount();
});

it('updates at maximum of `updateInterval` with a string `value`', (done) => {
const {intl} = intlProvider.getChildContext();

0 comments on commit 653cee7

Please sign in to comment.