Skip to content

feat(definedWatch): new filter #504

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

Closed
wants to merge 2 commits into from

Conversation

Shinigami92
Copy link
Contributor

This is a new filter / watcher that only triggers when the source is currently not null or not undefined

It should also be combinable with other filters so that in example a debounceFilter works together with a definedFilter and therefore only triggers after some debounce time but only when the value was defined

This is useful for watching a stream of data but only pass the defined values instead of wrapping the body of the filter with an if statement like

watch(source, (value) => {
  if (value != null) {
    // do stuff
  }
})

I'm thinking this further and we could create a filter where you can pass a predicate 🤔

Maybe

xyWatch(
  source,
  (value) => { console.log(value) },
  { predicate: (value) => value != null }
)

xyWatch(
  source,
  (value) => { console.log(value) },
  { predicate: (value) => value >= 42 }
)

import { myFun } from 'abc'

xyWatch(
  source,
  (value) => { console.log(value) },
  { predicate: myFun }
)

@antfu
Copy link
Member

antfu commented May 13, 2021

Have you tried http://vueuse.org/whenever ?

@Shinigami92 Shinigami92 marked this pull request as draft May 13, 2021 09:25
@Shinigami92
Copy link
Contributor Author

Have you tried http://vueuse.org/whenever ?

Okay, some things are rushing to my head now 🙂, so everything below could be a little bit chaotic 😄

So at first: No, I didn't saw whenever yet and therefore didn't used it, cause I watched (:smile: pun intended) for it in the Watch section

BUT thinking my idea a bit further (over night and with help of sleep) some new ideas came up in my mind 😃

I have some sections in my codebase where I setup watchers that looks like this:

watch(source, (val, oldVal) => {
  if (oldVal && val.id !== oldVal.id) {
    // update stuff
  }
})

I'm thinking about that definedWatch could always skip null and undefined values and only trigger with an defined old value
So maybe we can do something like this: (not tested yet)

export function definedFilter() {
  let lastDefinedValue
  const filter: EventFilter = (invoke, options) => {
    if (options.args[0] != null) {
      lastDefinedValue = options.args[0]
      invoke() // find out how to pass `lastDefinedValue` as `oldVal` :thinking: 
    }
  }

  return filter
}

The benefit over whenever is especially the TypeScript support where you don't need to check for defined but val is specially typed with Exclude<T, null | undefined>
In whenever it could theoretically be null or undefined but practically not

whenever is useful for predicates like

whenever(
  () => typeof source.value === 'boolean', 
  () => console.log('It's definitiv a boolean!'),
)

But you need to now that whenever is a thing 🤔 It doesn't feel like a native watcher 🤔


Please let me now what you are thinking about my ideas and tell me everything you can think off which what I could improve this

This PR was originally intended to get a first real contact with the codebase of VueUse 🙂

@patak-dev
Copy link
Member

Maybe it could be split into two filters, as there are two different features: one similar to whenever and a new one hasChangedFilter? I think the filter that only fires when the value is different from the previous one is useful, possibly also allowing undefined or null if that is the type of the ref.
hasChangedWatch (but with a better name), a watch util based on this filter could also be interesting.

@Shinigami92
Copy link
Contributor Author

Maybe it could be split into two filters, as there are two different features: one similar to whenever and a new one hasChangedFilter? I think the filter that only fires when the value is different from the previous one is useful, possibly also allowing undefined or null if that is the type of the ref.
hasChangedWatch (but with a better name), a watch util based on this filter could also be interesting.

But "has changed" is already the default behavior of watchers 😅
Watchers are watching for changes 👀

@patak-dev
Copy link
Member

You are right, now I have to recall why I thought that each assignment will still trigger the watch. Ignore the noise then 😅
(Still may be interesting to have a hasChangedFilter that receives a compare function when shallow equality is not enough)

@Shinigami92
Copy link
Contributor Author

Shinigami92 commented May 14, 2021

You can still use whenever as Antfu pointed out, but it's a bit different now to this PR's watcher/filter, plus this watcher is specially typed for its purpose

@wheatjs
Copy link
Member

wheatjs commented May 15, 2021

Btw, I don't think we use stories anymore, so you probably don't have to include those files.

@Shinigami92
Copy link
Contributor Author

Btw, I don't think we use stories anymore, so you probably don't have to include those files.

Could you explain a little bit what these files are for? Cause I just copied over debouncedWatch


Also, do you all think definedWatch is a good name? Do you have an idea for a better name?

@wheatjs
Copy link
Member

wheatjs commented May 16, 2021

Could you explain a little bit what these files are for? Cause I just copied over debouncedWatch

I don't want to get too off topic, but index.stories.ts was for storybook which VueUse doesn't use anymore so it is not needed. For a better description on the structure of functions, you can checkout the contribute guide here https://vueuse.org/contributing.html#function-folder

Also, do you all think definedWatch is a good name? Do you have an idea for a better name?

Don't have any strong opinions here as I'm not the best at naming things to start with 😅

@Shinigami92
Copy link
Contributor Author

I think this is a to special case, and also it can so quickly be solved by just using an if inside the normal watcher 🤷
Or just pass a filter manually to the watchWithFilter

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

Successfully merging this pull request may close these issues.

4 participants