Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use getTime() to check for Date equality #3757

Open
davetapley opened this issue Sep 12, 2023 · 4 comments
Open

Use getTime() to check for Date equality #3757

davetapley opened this issue Sep 12, 2023 · 4 comments

Comments

@davetapley
Copy link

davetapley commented Sep 12, 2023

Intended outcome:

When updating observables from an API response which contains timestamps,
if a timestamp in the response is unchanged since the last time I updated,
I don't want autorun to trigger.

Actual outcome:

Because I cast the timestamps to a JS Date,
autorun is triggered,
even if the getTime() is the same.

How to reproduce the issue:

Open console on: https://codesandbox.io/s/autorun-new-date-2np493?file=/src/index.js

Observe:

  1. autorun doesn't log when clicking Finshed/Unfinished if already finished/unfinished
  2. 'Set now' buttons will always autorun because time is changing
  3. 'Set same' buttons differ in behavior: if 'Date' then will always autorun, if 'Time' then won't.

I'd argue that for 99.9999% of use cases you wouldn't want autorun to trigger,
because the actual 'value' hasn't changed.

See also:

@davetapley davetapley changed the title Use time equality for Date (not object equality) Use getTime() to check for Date equality Sep 12, 2023
@urugator
Copy link
Collaborator

urugator commented Sep 13, 2023

Do the check before mutating the observable.
The default comparator is === , which is fast, easy to explain and isn't surprising:

const date = new Date(whatever)
o.date = date;
assert(date === o.date); // always true

EDIT: Correction, default comparer seems to be Object.is

function defaultComparer(a: any, b: any): boolean {
if (Object.is) {
return Object.is(a, b)
}
return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b
}

but the point is the same

@davetapley
Copy link
Author

@urugator

Do the check before mutating the observable

Well, sure that would work, but I think MobX should do it internally because:

a. For 99.9999% of use cases you wouldn't want autorun to trigger in this case, and:
b. It's more consistent with how other primitives work (at least, bool, string and number, which I tested here)


I'm not sure how your snippet ⬇️ fits in?

const date = new Date(whatever)
o.date = date;
assert(date === o.date); // always true

Yes, that is true, but what's relevant is:

const date = new Date(whatever)
o.date = date; // triggers autorun ✅
o.date = date; // does not trigger autorun ✅
o.date = new Date(whatever) // triggers autorun ⛔️

A patten which is quite likely if whatever comes from an external API.

@urugator
Copy link
Collaborator

urugator commented Sep 15, 2023

triggers autorun

Autorun doesn't do any value diffing. The comparison is done when setting a value and if it's equal it's completely ignored - it's not set and autorun isn't notified. Autorun is guaranteed to run if state changed, so we can't mutate state without notifying autorun, we must do both or neither.

I'm not sure how your snippet ⬇️ fits in?

It's demonstrating an expectation, which would be broken if we would use a different comparison for date objects. The assigment operation would have a surprising behavior.

For 99.9999% of use cases you wouldn't want autorun to trigger in this case,

Can be said about any value like object, both builtin or proprietary. This also includes collections of value objects (array of dates etc). Btw we expose comparer.structural, which you can use:

// Strings, numbers, regular expressions, dates, and booleans are compared by value.

with how other primitives work

Date isn't primitive, similary to new Number(0), new Boolean(true). What's more Date is mutable, so if I assign date object somewhere and then mutate it, the expectation is that the assigned date is mutated as well.

@davetapley
Copy link
Author

Thanks for reply / clarifications @urugator.

I put most of my thoughts here: mobxjs/mobx-state-tree#2080 (comment)

Thanks for mentioning comparer.structural, I didn't know about that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants